@tensorlakeai/tensorlake 0.5.152 → 0.5.154

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 +3596 -3377
  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 +3559 -3340
  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 +1502 -880
  12. package/dist/index.cjs.map +1 -1
  13. package/dist/index.d.cts +366 -21
  14. package/dist/index.d.ts +366 -21
  15. package/dist/index.js +1475 -871
  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 +437 -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 +436 -1299
  26. package/dist/sandbox-image.js.map +1 -1
  27. package/package.json +7 -7
  28. package/runtime/function-executor/manifest.json +5 -5
  29. package/runtime/function-executor/package/dist/function-executor/main.js +2 -2
  30. package/runtime/function-executor/package/npm-shrinkwrap.json +2 -2
  31. package/runtime/function-executor/package/package.json +1 -1
  32. package/runtime/typescript-function-runner/manifest.json +5 -5
  33. package/runtime/typescript-function-runner/package/dist/function-agent/main.js +1 -1
  34. package/runtime/typescript-function-runner/package/npm-shrinkwrap.json +26 -26
  35. package/runtime/typescript-function-runner/package/package.json +7 -7
package/dist/index.cjs CHANGED
@@ -49,7 +49,7 @@ var init_defaults = __esm({
49
49
  "src/defaults.ts"() {
50
50
  "use strict";
51
51
  init_cjs_shims();
52
- SDK_VERSION = "0.5.152";
52
+ SDK_VERSION = "0.5.154";
53
53
  API_URL = process.env.TENSORLAKE_API_URL ?? "https://api.tensorlake.ai";
54
54
  API_KEY = process.env.TENSORLAKE_API_KEY ?? void 0;
55
55
  NAMESPACE = process.env.INDEXIFY_NAMESPACE ?? "default";
@@ -60,6 +60,20 @@ var init_defaults = __esm({
60
60
  }
61
61
  });
62
62
 
63
+ // src/enum.ts
64
+ function enumValue(values, value) {
65
+ return typeof value === "string" && Object.values(values).includes(value) ? value : values.UNKNOWN;
66
+ }
67
+ function withRaw(value, raw) {
68
+ return Object.defineProperty(value, "raw", { value: raw, enumerable: false, configurable: true });
69
+ }
70
+ var init_enum = __esm({
71
+ "src/enum.ts"() {
72
+ "use strict";
73
+ init_cjs_shims();
74
+ }
75
+ });
76
+
63
77
  // src/errors.ts
64
78
  function formatErrorDetails(errorDetails) {
65
79
  if (errorDetails == null) return void 0;
@@ -498,7 +512,7 @@ var init_native_worker_client = __esm({
498
512
  }
499
513
  };
500
514
  runtimeKey = /* @__PURE__ */ Symbol.for(
501
- `tensorlake.native.worker.${false ? "source" : "0.5.152"}.v1`
515
+ `tensorlake.native.worker.${false ? "source" : "0.5.154"}.v1`
502
516
  );
503
517
  runtimes = globalThis;
504
518
  }
@@ -598,6 +612,9 @@ var init_models = __esm({
598
612
  SnapshotStatus2["LOCAL_READY"] = "local_ready";
599
613
  SnapshotStatus2["COMPLETED"] = "completed";
600
614
  SnapshotStatus2["FAILED"] = "failed";
615
+ SnapshotStatus2["DELETING"] = "deleting";
616
+ SnapshotStatus2["REPLICATING"] = "replicating";
617
+ SnapshotStatus2["UNKNOWN"] = "unknown";
601
618
  return SnapshotStatus2;
602
619
  })(SnapshotStatus || {});
603
620
  ProcessStatus = /* @__PURE__ */ ((ProcessStatus2) => {
@@ -3886,9 +3903,8 @@ var init_sandbox = __esm({
3886
3903
  *
3887
3904
  * Resource targets use create's cpus, memoryMb, and diskMb names. Resize
3888
3905
  * waits by default; wait=false returns admission. Timeout does not cancel it.
3889
- * CPU-only CAS sandboxes support CPU, memory, and root-disk resize; GPU CAS sandboxes
3890
- * support only root-disk growth and reject CPU and memory changes.
3891
- * Non-CAS sandboxes do not support live resize.
3906
+ * Which runtimes and dimensions support a live resize is decided by the
3907
+ * server, whose policy error is thrown unchanged.
3892
3908
  * Wait, timeout, and pollInterval are ignored on non-resource updates.
3893
3909
  * A no-op returns current resources with absent or earlier resize metadata.
3894
3910
  *
@@ -4306,29 +4322,29 @@ var init_sandbox = __esm({
4306
4322
  }
4307
4323
  // --- File operations ---
4308
4324
  /** Read a file from the sandbox and return its raw bytes. */
4309
- async readFile(path3) {
4325
+ async readFile(path4) {
4310
4326
  const proxy = await this.proxy.client();
4311
- const { traceId, data } = await callNative(() => proxy.readFile(path3), {
4327
+ const { traceId, data } = await callNative(() => proxy.readFile(path4), {
4312
4328
  sandboxId: this.sandboxId
4313
4329
  });
4314
4330
  return Object.assign(Uint8Array.from(data), { traceId });
4315
4331
  }
4316
4332
  /** Write raw bytes to a file in the sandbox, creating it if it does not exist. */
4317
- async writeFile(path3, content) {
4333
+ async writeFile(path4, content) {
4318
4334
  const proxy = await this.proxy.client();
4319
- await callNative(() => proxy.writeFile(path3, Buffer.from(content)), {
4335
+ await callNative(() => proxy.writeFile(path4, Buffer.from(content)), {
4320
4336
  sandboxId: this.sandboxId
4321
4337
  });
4322
4338
  }
4323
4339
  /** Delete a file from the sandbox. */
4324
- async deleteFile(path3) {
4340
+ async deleteFile(path4) {
4325
4341
  const proxy = await this.proxy.client();
4326
- await callNative(() => proxy.deleteFile(path3), { sandboxId: this.sandboxId });
4342
+ await callNative(() => proxy.deleteFile(path4), { sandboxId: this.sandboxId });
4327
4343
  }
4328
4344
  /** List the contents of a directory in the sandbox. */
4329
- async listDirectory(path3) {
4345
+ async listDirectory(path4) {
4330
4346
  const proxy = await this.proxy.client();
4331
- const { traceId, json } = await callNative(() => proxy.listDirectory(path3), {
4347
+ const { traceId, json } = await callNative(() => proxy.listDirectory(path4), {
4332
4348
  sandboxId: this.sandboxId
4333
4349
  });
4334
4350
  return Object.assign(fromSnakeKeys(JSON.parse(json)), {
@@ -4495,6 +4511,18 @@ __export(client_exports, {
4495
4511
  DEFAULT_WAIT_POLL_INTERVAL_SEC: () => DEFAULT_WAIT_POLL_INTERVAL_SEC,
4496
4512
  SandboxClient: () => SandboxClient
4497
4513
  });
4514
+ function parseSnapshot(raw) {
4515
+ if (raw === null || typeof raw !== "object" || Array.isArray(raw)) {
4516
+ throw new SandboxError("Invalid snapshot response: expected an object");
4517
+ }
4518
+ if (raw.status == null) {
4519
+ throw new SandboxError("Invalid snapshot response: missing status");
4520
+ }
4521
+ return withRaw({
4522
+ ...fromSnakeKeys(raw, "snapshotId"),
4523
+ status: enumValue(SnapshotStatus, raw.status)
4524
+ }, raw);
4525
+ }
4498
4526
  function requireReadOnlySnapshotPin(fileSystemId, mountPath, readOnly, snapshotId) {
4499
4527
  if (snapshotId != null && readOnly !== true) {
4500
4528
  throw new SandboxError(
@@ -4616,6 +4644,7 @@ var init_client = __esm({
4616
4644
  "use strict";
4617
4645
  init_cjs_shims();
4618
4646
  init_defaults();
4647
+ init_enum();
4619
4648
  init_errors();
4620
4649
  init_native_worker_client();
4621
4650
  init_native_sandbox();
@@ -4994,9 +5023,9 @@ var init_client = __esm({
4994
5023
  });
4995
5024
  }
4996
5025
  /**
4997
- * Update properties or resize a running sandbox. CPU-only CAS sandboxes support
4998
- * CPU, memory, and root-disk resize; GPU CAS sandboxes support only root-disk
4999
- * growth. Non-CAS sandboxes do not support live resize.
5026
+ * Update properties or resize a running sandbox. Which runtimes and
5027
+ * dimensions support a live resize is decided by the server, whose policy
5028
+ * error is thrown unchanged.
5000
5029
  * Resource names match create. Resize waits by default; wait=false returns
5001
5030
  * admission. Timeout leaves the resize running and reports its generation.
5002
5031
  * Wait, timeout, and pollInterval are ignored on non-resource updates.
@@ -5263,18 +5292,18 @@ var init_client = __esm({
5263
5292
  * block automatically.
5264
5293
  */
5265
5294
  async snapshot(sandboxId, options) {
5266
- return this.plainJson(
5295
+ const { json } = await callNative(
5267
5296
  () => this.native.createSnapshot(sandboxId, options?.snapshotType ?? null),
5268
- "snapshotId",
5269
5297
  { sandboxId, notFoundKind: "sandbox" }
5270
5298
  );
5299
+ return parseSnapshot(JSON.parse(json));
5271
5300
  }
5272
5301
  /** Get current status and metadata for a snapshot by ID. */
5273
5302
  async getSnapshot(snapshotId) {
5274
- return this.tracedJson(
5275
- () => this.native.getSnapshot(snapshotId),
5276
- "snapshotId"
5303
+ const { traceId, json } = await callNative(
5304
+ () => this.native.getSnapshot(snapshotId)
5277
5305
  );
5306
+ return Object.assign(parseSnapshot(JSON.parse(json)), { traceId });
5278
5307
  }
5279
5308
  /** List all snapshots in the namespace. */
5280
5309
  async listSnapshots() {
@@ -5282,9 +5311,14 @@ var init_client = __esm({
5282
5311
  () => this.native.listSnapshots()
5283
5312
  );
5284
5313
  const parsed = JSON.parse(json);
5285
- const snapshots = (parsed.snapshots ?? []).map(
5286
- (s) => fromSnakeKeys(s, "snapshotId")
5287
- );
5314
+ if (parsed !== null && (typeof parsed !== "object" || Array.isArray(parsed))) {
5315
+ throw new SandboxError("Invalid snapshot list response: expected an object");
5316
+ }
5317
+ const records = parsed?.snapshots ?? [];
5318
+ if (!Array.isArray(records)) {
5319
+ throw new SandboxError("Invalid snapshot list response: snapshots must be an array");
5320
+ }
5321
+ const snapshots = records.map((s) => parseSnapshot(s));
5288
5322
  return Object.assign(snapshots, { traceId });
5289
5323
  }
5290
5324
  /** Delete a snapshot by ID. */
@@ -5315,6 +5349,11 @@ var init_client = __esm({
5315
5349
  `Snapshot ${result.snapshotId} failed: ${info.error}`
5316
5350
  );
5317
5351
  }
5352
+ if (info.status === "deleting" /* DELETING */) {
5353
+ throw new SandboxError(
5354
+ `Snapshot ${result.snapshotId} is being deleted`
5355
+ );
5356
+ }
5318
5357
  await sleep2(pollInterval * 1e3);
5319
5358
  }
5320
5359
  throw new SandboxError(
@@ -5572,694 +5611,115 @@ var init_client = __esm({
5572
5611
  }
5573
5612
  });
5574
5613
 
5575
- // src/native-cloud.ts
5576
- async function serializeRequest(method, path3, options) {
5577
- const headers = { ...options?.headers };
5578
- let body = options?.body;
5579
- if (options?.json !== void 0) {
5580
- body = JSON.stringify(options.json);
5581
- if (!Object.keys(headers).some((key) => key.toLowerCase() === "content-type")) {
5582
- headers["Content-Type"] = "application/json";
5583
- }
5584
- }
5585
- const request = {
5586
- method,
5587
- path: path3,
5588
- headersJson: JSON.stringify(headers),
5589
- statusOnlyCodes: [...options?.statusOnlyCodes ?? []]
5614
+ // src/image.ts
5615
+ function cloneOperation(op) {
5616
+ return {
5617
+ type: op.type,
5618
+ args: [...op.args],
5619
+ options: { ...op.options }
5590
5620
  };
5591
- if (body instanceof FormData) {
5592
- request.parts = [];
5593
- for (const [name, value] of body.entries()) {
5594
- request.parts.push(typeof value === "string" ? { name, data: Buffer.from(value) } : { name, data: Buffer.from(await value.arrayBuffer()), filename: value.name, contentType: value.type || "application/octet-stream" });
5595
- }
5596
- } else if (body !== void 0) {
5597
- if (body instanceof Blob) request.body = Buffer.from(await body.arrayBuffer());
5598
- else if (typeof body === "string") request.body = Buffer.from(body);
5599
- else if (body instanceof ArrayBuffer) request.body = Buffer.from(new Uint8Array(body));
5600
- else request.body = Buffer.from(body);
5621
+ }
5622
+ function renderOptions(options) {
5623
+ const entries = Object.entries(options);
5624
+ if (entries.length === 0) {
5625
+ return "";
5601
5626
  }
5602
- return request;
5627
+ return ` ${entries.map(([key, value]) => `--${key}=${value}`).join(" ")}`;
5628
+ }
5629
+ function renderBuildOp(op) {
5630
+ const options = renderOptions(op.options);
5631
+ if (op.type === ImageBuildOperationType.ENV) {
5632
+ return `ENV${options} ${op.args[0]}=${JSON.stringify(op.args[1])}`;
5633
+ }
5634
+ return `${op.type}${options} ${op.args.join(" ")}`;
5635
+ }
5636
+ function dockerfileContent(image) {
5637
+ const lines = image.baseImage == null ? [] : [`FROM ${image.baseImage}`];
5638
+ lines.push(...image.buildOperations.map((op) => renderBuildOp(op)));
5639
+ return lines.join("\n");
5603
5640
  }
5604
- var NativeCloudTransport;
5605
- var init_native_cloud = __esm({
5606
- "src/native-cloud.ts"() {
5641
+ var import_node_crypto, DEFAULT_IMAGE_NAME, ImageBuildOperationType, Image;
5642
+ var init_image = __esm({
5643
+ "src/image.ts"() {
5607
5644
  "use strict";
5608
5645
  init_cjs_shims();
5609
- init_native_sandbox();
5610
- init_native_worker_client();
5611
- NativeCloudTransport = class {
5612
- constructor(options) {
5613
- this.options = options;
5614
- if (!Number.isSafeInteger(options.maxRetries) || options.maxRetries < 0 || options.maxRetries > 4294967295) {
5615
- throw new RangeError("maxRetries must be a non-negative 32-bit integer");
5616
- }
5617
- if (!Number.isFinite(options.retryBackoffMs) || options.retryBackoffMs < 0) {
5618
- throw new RangeError("retryBackoffMs must be a non-negative finite number");
5646
+ import_node_crypto = require("crypto");
5647
+ DEFAULT_IMAGE_NAME = "default";
5648
+ ImageBuildOperationType = {
5649
+ ADD: "ADD",
5650
+ COPY: "COPY",
5651
+ ENV: "ENV",
5652
+ RUN: "RUN",
5653
+ WORKDIR: "WORKDIR"
5654
+ };
5655
+ Image = class {
5656
+ _id;
5657
+ _name;
5658
+ _tag;
5659
+ _baseImage;
5660
+ _buildOperations;
5661
+ constructor(nameOrOptions = {}, tag = "latest", baseImage = null) {
5662
+ this._id = (0, import_node_crypto.randomUUID)();
5663
+ this._buildOperations = [];
5664
+ if (typeof nameOrOptions === "string") {
5665
+ this._name = nameOrOptions;
5666
+ this._tag = tag;
5667
+ this._baseImage = baseImage;
5668
+ return;
5619
5669
  }
5670
+ this._name = nameOrOptions.name ?? DEFAULT_IMAGE_NAME;
5671
+ this._tag = nameOrOptions.tag ?? "latest";
5672
+ this._baseImage = nameOrOptions.baseImage ?? null;
5620
5673
  }
5621
- native;
5622
- closed = false;
5623
- client() {
5624
- if (this.closed) throw new Error("Tensorlake native client is closed");
5625
- if (this.native) return this.native;
5626
- const ctor = loadNativeSandboxBinding().NativeCloudClient;
5627
- if (!ctor) throw new Error("Native binding does not export NativeCloudClient; rebuild with 'npm run build:native'");
5628
- return this.native = new ctor(JSON.stringify(this.options));
5674
+ get name() {
5675
+ return this._name;
5629
5676
  }
5630
- close() {
5631
- this.closed = true;
5632
- releaseNativeHandle(this.native ?? null);
5633
- this.native = void 0;
5634
- }
5635
- async requestResponse(method, path3, options) {
5636
- const request = await serializeRequest(method, path3, options);
5637
- const raw = await callNative(() => this.client().request(request));
5638
- const response = new Response(
5639
- [204, 205, 304].includes(raw.status) ? null : Uint8Array.from(raw.data).buffer,
5640
- { status: raw.status, headers: JSON.parse(raw.headersJson) }
5641
- );
5642
- return Object.assign(response, { traceId: raw.traceId });
5677
+ get tag() {
5678
+ return this._tag;
5643
5679
  }
5644
- async requestJson(method, path3) {
5645
- const response = await this.requestResponse(method, path3);
5646
- const text = await response.text();
5647
- const value = text ? JSON.parse(text) : null;
5648
- return Object.assign(value ?? {}, { traceId: response.traceId });
5680
+ get baseImage() {
5681
+ return this._baseImage;
5649
5682
  }
5650
- async *stream(method, path3, signal) {
5651
- if (signal?.aborted) return;
5652
- const request = await serializeRequest(method, path3, { headers: { Accept: "text/event-stream" } });
5653
- yield* nativeEventStream((emit) => this.client().stream(request, emit), void 0, signal);
5683
+ get buildOperations() {
5684
+ return this._buildOperations.map(cloneOperation);
5654
5685
  }
5655
- };
5656
- }
5657
- });
5658
-
5659
- // src/cloud-client.ts
5660
- function secretFromMetadata(metadata) {
5661
- return {
5662
- id: metadata.id,
5663
- name: metadata.name,
5664
- createdAt: new Date(metadata.created_at_ms)
5665
- };
5666
- }
5667
- function applicationAllowsUnauthenticatedRequests(manifest) {
5668
- return Array.isArray(manifest.allow) && manifest.allow.includes(UNAUTHENTICATED_REQUESTS);
5669
- }
5670
- function publicEndpointIdFromManifest(manifest) {
5671
- for (const key of ["public_endpoint_id", "publicEndpointId"]) {
5672
- const value = manifest[key];
5673
- if (typeof value === "string" && value.length > 0) {
5674
- return value;
5675
- }
5676
- }
5677
- return void 0;
5678
- }
5679
- function generatePublicEndpointId() {
5680
- return `endpoint_${(0, import_nanoid.nanoid)()}`;
5681
- }
5682
- function createApplicationBuildForm(request, imageContexts) {
5683
- const contextsByPartName = /* @__PURE__ */ new Map();
5684
- for (const context of imageContexts) {
5685
- if (contextsByPartName.has(context.contextTarPartName)) {
5686
- throw new Error(
5687
- `duplicate image context part name '${context.contextTarPartName}'`
5688
- );
5689
- }
5690
- contextsByPartName.set(context.contextTarPartName, context);
5691
- }
5692
- const form = new FormData();
5693
- form.append(
5694
- "app_version",
5695
- new Blob([JSON.stringify(request)], { type: "application/json" }),
5696
- "app_version"
5697
- );
5698
- for (const image of request.images) {
5699
- const context = contextsByPartName.get(image.contextTarPartName);
5700
- if (!context) {
5701
- throw new Error(
5702
- `missing image context for part '${image.contextTarPartName}'`
5703
- );
5704
- }
5705
- form.append(
5706
- image.contextTarPartName,
5707
- new Blob([toBlobPart(context.contextTarGz)]),
5708
- `${image.contextTarPartName}.tar.gz`
5709
- );
5710
- }
5711
- for (const context of imageContexts) {
5712
- if (!request.images.some((image) => image.contextTarPartName === context.contextTarPartName)) {
5713
- throw new Error(
5714
- `unexpected image context for part '${context.contextTarPartName}'`
5715
- );
5716
- }
5717
- }
5718
- return form;
5719
- }
5720
- function trimTrailingSlashes2(value) {
5721
- return value.endsWith("/") ? value.slice(0, -1) : value;
5722
- }
5723
- function nextRequestPath(next) {
5724
- const schemeIndex = next.indexOf("://");
5725
- if (schemeIndex !== -1) {
5726
- const afterScheme = next.slice(schemeIndex + 3);
5727
- const slashIndex = afterScheme.indexOf("/");
5728
- return slashIndex === -1 ? "/" : afterScheme.slice(slashIndex);
5729
- }
5730
- return next.startsWith("/") ? next : `/${next}`;
5731
- }
5732
- function toBlobPart(data) {
5733
- if (typeof data === "string" || data instanceof Blob) {
5734
- return data;
5735
- }
5736
- if (data instanceof Uint8Array) {
5737
- return Uint8Array.from(data).buffer;
5738
- }
5739
- return data;
5740
- }
5741
- function toRequestBody(data) {
5742
- return toBlobPart(data);
5743
- }
5744
- async function parseJsonResponse(response) {
5745
- const text = await response.text();
5746
- if (!text) {
5747
- return void 0;
5748
- }
5749
- return JSON.parse(text);
5750
- }
5751
- var import_nanoid, CloudClient, UNAUTHENTICATED_REQUESTS;
5752
- var init_cloud_client = __esm({
5753
- "src/cloud-client.ts"() {
5754
- "use strict";
5755
- init_cjs_shims();
5756
- import_nanoid = require("nanoid");
5757
- init_defaults();
5758
- init_native_cloud();
5759
- init_models();
5760
- CloudClient = class _CloudClient {
5761
- transport;
5762
- organizationId;
5763
- projectId;
5764
- namespace;
5765
- constructor(options) {
5766
- this.organizationId = options?.organizationId;
5767
- this.projectId = options?.projectId;
5768
- this.namespace = options?.namespace ?? NAMESPACE;
5769
- this.transport = new NativeCloudTransport({
5770
- baseUrl: options?.apiUrl ?? API_URL,
5771
- apiKey: options?.apiKey ?? API_KEY,
5772
- organizationId: this.organizationId,
5773
- projectId: this.projectId,
5774
- maxRetries: options?.maxRetries ?? MAX_RETRIES,
5775
- retryBackoffMs: options?.retryBackoffMs ?? RETRY_BACKOFF_MS,
5776
- timeoutMs: DEFAULT_HTTP_TIMEOUT_MS,
5777
- userAgent: `tensorlake-typescript-sdk/${SDK_VERSION}`
5686
+ add(src, dest, options = void 0) {
5687
+ return this._addOperation({
5688
+ type: ImageBuildOperationType.ADD,
5689
+ args: [src, dest],
5690
+ options: options == null ? {} : { ...options }
5778
5691
  });
5779
5692
  }
5780
- static forCloud(options) {
5781
- return new _CloudClient(options);
5693
+ copy(src, dest, options = void 0) {
5694
+ return this._addOperation({
5695
+ type: ImageBuildOperationType.COPY,
5696
+ args: [src, dest],
5697
+ options: options == null ? {} : { ...options }
5698
+ });
5782
5699
  }
5783
- close() {
5784
- this.transport.close();
5785
- }
5786
- async upsertApplication(manifest, codeZip, upgradeRunningRequests = false) {
5787
- const applicationManifest = { ...manifest };
5788
- let publicEndpointId = publicEndpointIdFromManifest(applicationManifest);
5789
- if (applicationAllowsUnauthenticatedRequests(applicationManifest) && publicEndpointId === void 0) {
5790
- const applicationName = applicationManifest.name;
5791
- if (typeof applicationName === "string" && applicationName.length > 0) {
5792
- publicEndpointId = await this.existingApplicationPublicEndpointId(applicationName);
5793
- }
5794
- publicEndpointId ??= generatePublicEndpointId();
5795
- }
5796
- if (publicEndpointId !== void 0) {
5797
- applicationManifest.public_endpoint_id = publicEndpointId;
5798
- delete applicationManifest.publicEndpointId;
5799
- }
5800
- const form = new FormData();
5801
- form.append(
5802
- "code",
5803
- new Blob([toBlobPart(codeZip)], { type: "application/zip" }),
5804
- "code.zip"
5805
- );
5806
- form.append("code_content_type", "application/zip");
5807
- form.append("application", JSON.stringify(applicationManifest));
5808
- form.append(
5809
- "upgrade_requests_to_latest_code",
5810
- String(upgradeRunningRequests)
5811
- );
5812
- await this.transport.requestResponse("POST", this.namespacePath("applications"), {
5813
- body: form
5700
+ env(key, value) {
5701
+ return this._addOperation({
5702
+ type: ImageBuildOperationType.ENV,
5703
+ args: [key, value],
5704
+ options: {}
5814
5705
  });
5815
5706
  }
5816
- async deleteApplication(applicationName) {
5817
- await this.transport.requestResponse(
5818
- "DELETE",
5819
- this.namespacePath(`applications/${encodeURIComponent(applicationName)}`)
5820
- );
5707
+ run(commands, options = void 0) {
5708
+ return this._addOperation({
5709
+ type: ImageBuildOperationType.RUN,
5710
+ args: Array.isArray(commands) ? [...commands] : [commands],
5711
+ options: options == null ? {} : { ...options }
5712
+ });
5821
5713
  }
5822
- async deleteSandboxImage(imageName) {
5823
- await this.transport.requestResponse(
5824
- "DELETE",
5825
- this.namespacePath(`sandbox-images/${encodeURIComponent(imageName)}`)
5826
- );
5714
+ workdir(directory) {
5715
+ return this._addOperation({
5716
+ type: ImageBuildOperationType.WORKDIR,
5717
+ args: [directory],
5718
+ options: {}
5719
+ });
5827
5720
  }
5828
5721
  /**
5829
- * Look up a registered sandbox image (template) by its registered name.
5830
- *
5831
- * Returns the template, or `null` when no image with that name exists.
5832
- * API-key clients may omit organization/project IDs and use the
5833
- * token-scoped Platform API route directly. Explicit scope remains
5834
- * available for PAT callers.
5835
- */
5836
- async findSandboxImageByName(imageName, options) {
5837
- const base = this.platformProjectPath(
5838
- "sandbox-templates",
5839
- options?.organizationId,
5840
- options?.projectId
5841
- );
5842
- const response = await this.transport.requestResponse(
5843
- "GET",
5844
- `${base}/by-name/${encodeURIComponent(imageName)}`,
5845
- { statusOnlyCodes: /* @__PURE__ */ new Set([404]) }
5846
- );
5847
- if (response.status === 404) {
5848
- return null;
5849
- }
5850
- const raw = await parseJsonResponse(response);
5851
- return fromSnakeKeys(raw);
5852
- }
5853
- /**
5854
- * List all registered sandbox images (templates), following pagination to
5855
- * the end. API-key clients may omit organization/project IDs and use the
5856
- * token-scoped Platform API route directly.
5857
- */
5858
- async listSandboxImages(options) {
5859
- const base = this.platformProjectPath(
5860
- "sandbox-templates",
5861
- options?.organizationId,
5862
- options?.projectId
5863
- );
5864
- let path3 = `${base}?pageSize=100`;
5865
- const templates = [];
5866
- while (path3 !== null) {
5867
- const page = await this.transport.requestJson(
5868
- "GET",
5869
- path3
5870
- );
5871
- for (const item of page.items ?? []) {
5872
- templates.push(fromSnakeKeys(item));
5873
- }
5874
- const next = page.pagination?.next;
5875
- path3 = next ? nextRequestPath(next) : null;
5876
- }
5877
- return templates;
5878
- }
5879
- async applications() {
5880
- const raw = await this.transport.requestJson(
5881
- "GET",
5882
- this.namespacePath("applications")
5883
- );
5884
- return (raw.applications ?? []).map(
5885
- (application) => fromSnakeKeys(application)
5886
- );
5887
- }
5888
- async applicationManifest(applicationName) {
5889
- const raw = await this.transport.requestJson(
5890
- "GET",
5891
- this.namespacePath(`applications/${encodeURIComponent(applicationName)}`)
5892
- );
5893
- return fromSnakeKeys(raw);
5894
- }
5895
- async runRequest(applicationName, inputs = []) {
5896
- const path3 = this.namespacePath(
5897
- `applications/${encodeURIComponent(applicationName)}`
5898
- );
5899
- const response = inputs.length === 0 ? await this.transport.requestResponse("POST", path3, {
5900
- body: new Uint8Array(),
5901
- headers: { Accept: "application/json" }
5902
- }) : inputs.length === 1 && inputs[0].name === "0" ? await this.transport.requestResponse("POST", path3, {
5903
- body: toRequestBody(inputs[0].data),
5904
- headers: {
5905
- Accept: "application/json",
5906
- "Content-Type": inputs[0].contentType
5907
- }
5908
- }) : await this.runMultipartRequest(path3, inputs);
5909
- const body = await parseJsonResponse(response);
5910
- const requestId = body?.request_id;
5911
- if (!requestId) {
5912
- throw new Error("missing request_id in run request response body");
5913
- }
5914
- return requestId;
5915
- }
5916
- async waitOnRequestCompletion(applicationName, requestId) {
5917
- const stream = this.transport.stream(
5918
- "GET",
5919
- this.namespacePath(
5920
- `applications/${encodeURIComponent(applicationName)}/requests/${encodeURIComponent(requestId)}/progress`
5921
- )
5922
- );
5923
- for await (const event of stream) {
5924
- if (Object.prototype.hasOwnProperty.call(event, "RequestFinished")) {
5925
- return;
5926
- }
5927
- }
5928
- throw new Error("progress stream ended before request completion");
5929
- }
5930
- async requestMetadata(applicationName, requestId) {
5931
- const raw = await this.transport.requestJson(
5932
- "GET",
5933
- this.namespacePath(
5934
- `applications/${encodeURIComponent(applicationName)}/requests/${encodeURIComponent(requestId)}`
5935
- )
5936
- );
5937
- return fromSnakeKeys(raw);
5938
- }
5939
- async requestOutput(applicationName, requestId) {
5940
- const response = await this.transport.requestResponse(
5941
- "GET",
5942
- this.namespacePath(
5943
- `applications/${encodeURIComponent(applicationName)}/requests/${encodeURIComponent(requestId)}/output`
5944
- )
5945
- );
5946
- const serializedValue = new Uint8Array(await response.arrayBuffer());
5947
- const contentType = response.headers.get("content-type") ?? "";
5948
- return {
5949
- serializedValue,
5950
- contentType
5951
- };
5952
- }
5953
- async listSecrets(options) {
5954
- const base = this.secretCollectionPath(
5955
- options?.organizationId,
5956
- options?.projectId
5957
- );
5958
- const raw = await this.transport.requestJson("GET", base);
5959
- const pageSize = Math.max(0, options?.pageSize ?? 100);
5960
- return Object.assign(
5961
- {
5962
- items: raw.slice(0, pageSize).map(secretFromMetadata),
5963
- pagination: { total: raw.length }
5964
- },
5965
- { traceId: raw.traceId }
5966
- );
5967
- }
5968
- async getSecret(secretId, options) {
5969
- const base = this.secretCollectionPath(
5970
- options?.organizationId,
5971
- options?.projectId
5972
- );
5973
- const raw = await this.transport.requestJson(
5974
- "GET",
5975
- `${base}/${encodeURIComponent(secretId)}`
5976
- );
5977
- return Object.assign(secretFromMetadata(raw), { traceId: raw.traceId });
5978
- }
5979
- async upsertSecrets(secrets, options) {
5980
- const base = this.secretCollectionPath(
5981
- options?.organizationId,
5982
- options?.projectId
5983
- );
5984
- if (Array.isArray(secrets)) {
5985
- const results = [];
5986
- for (const secret of secrets) {
5987
- results.push(await this.upsertSecret(base, secret));
5988
- }
5989
- return results;
5990
- }
5991
- return this.upsertSecret(base, secrets);
5992
- }
5993
- async deleteSecret(secretId, options) {
5994
- const base = this.secretCollectionPath(
5995
- options?.organizationId,
5996
- options?.projectId
5997
- );
5998
- await this.transport.requestResponse(
5999
- "DELETE",
6000
- `${base}/${encodeURIComponent(secretId)}`
6001
- );
6002
- }
6003
- async upsertSecret(base, secret) {
6004
- let response = await this.transport.requestResponse("POST", base, {
6005
- json: secret,
6006
- headers: { "Idempotency-Key": (0, import_nanoid.nanoid)() },
6007
- statusOnlyCodes: /* @__PURE__ */ new Set([409])
6008
- });
6009
- if (response.status === 409) {
6010
- const prefix = base.slice(0, -"/secrets".length);
6011
- const existing = await this.transport.requestJson(
6012
- "GET",
6013
- `${prefix}/secret-names/${encodeURIComponent(secret.name)}`
6014
- );
6015
- response = await this.transport.requestResponse(
6016
- "POST",
6017
- `${base}/${encodeURIComponent(existing.id)}/versions`,
6018
- {
6019
- json: { value: secret.value },
6020
- headers: { "Idempotency-Key": (0, import_nanoid.nanoid)() }
6021
- }
6022
- );
6023
- }
6024
- const metadata = await parseJsonResponse(response);
6025
- return Object.assign(secretFromMetadata(metadata), {
6026
- traceId: response.traceId
6027
- });
6028
- }
6029
- async startImageBuild(buildServicePath, request) {
6030
- const form = new FormData();
6031
- form.append("graph_name", request.applicationName);
6032
- form.append("graph_version", request.applicationVersion);
6033
- form.append("graph_function_name", request.functionName);
6034
- form.append("image_name", request.imageName);
6035
- form.append("image_id", request.imageId);
6036
- form.append(
6037
- "context",
6038
- new Blob([toBlobPart(request.buildContext)]),
6039
- "context.tar.gz"
6040
- );
6041
- const response = await this.transport.requestResponse(
6042
- "PUT",
6043
- `${trimTrailingSlashes2(buildServicePath)}/builds`,
6044
- { body: form }
6045
- );
6046
- const raw = await parseJsonResponse(response);
6047
- return fromSnakeKeys(raw);
6048
- }
6049
- async createApplicationBuild(buildServicePath, request, imageContexts) {
6050
- const form = createApplicationBuildForm(request, imageContexts);
6051
- const response = await this.transport.requestResponse(
6052
- "POST",
6053
- trimTrailingSlashes2(buildServicePath),
6054
- { body: form }
6055
- );
6056
- const raw = await parseJsonResponse(response);
6057
- return fromSnakeKeys(raw);
6058
- }
6059
- async applicationBuildInfo(buildServicePath, applicationBuildId) {
6060
- const raw = await this.transport.requestJson(
6061
- "GET",
6062
- `${trimTrailingSlashes2(buildServicePath)}/${encodeURIComponent(applicationBuildId)}`
6063
- );
6064
- return fromSnakeKeys(raw);
6065
- }
6066
- async cancelApplicationBuild(buildServicePath, applicationBuildId) {
6067
- const raw = await this.transport.requestJson(
6068
- "POST",
6069
- `${trimTrailingSlashes2(buildServicePath)}/${encodeURIComponent(applicationBuildId)}/cancel`
6070
- );
6071
- return fromSnakeKeys(raw);
6072
- }
6073
- async buildInfo(buildServicePath, buildId) {
6074
- const raw = await this.transport.requestJson(
6075
- "GET",
6076
- `${trimTrailingSlashes2(buildServicePath)}/builds/${encodeURIComponent(buildId)}`
6077
- );
6078
- return fromSnakeKeys(raw);
6079
- }
6080
- async cancelBuild(buildServicePath, buildId) {
6081
- await this.transport.requestResponse(
6082
- "POST",
6083
- `${trimTrailingSlashes2(buildServicePath)}/builds/${encodeURIComponent(buildId)}/cancel`
6084
- );
6085
- }
6086
- async *streamBuildLogs(buildServicePath, buildId, signal) {
6087
- const stream = this.transport.stream(
6088
- "GET",
6089
- `${trimTrailingSlashes2(buildServicePath)}/builds/${encodeURIComponent(buildId)}/logs`,
6090
- signal
6091
- );
6092
- for await (const event of stream) {
6093
- yield fromSnakeKeys(event);
6094
- }
6095
- }
6096
- async runMultipartRequest(path3, inputs) {
6097
- const form = new FormData();
6098
- for (const input of inputs) {
6099
- form.append(
6100
- input.name,
6101
- new Blob([toBlobPart(input.data)], { type: input.contentType }),
6102
- input.name
6103
- );
6104
- }
6105
- return this.transport.requestResponse("POST", path3, {
6106
- body: form,
6107
- headers: { Accept: "application/json" }
6108
- });
6109
- }
6110
- namespacePath(subpath) {
6111
- return `/v1/namespaces/${encodeURIComponent(this.namespace)}/${subpath.replace(/^\/+/, "")}`;
6112
- }
6113
- async existingApplicationPublicEndpointId(applicationName) {
6114
- const response = await this.transport.requestResponse(
6115
- "GET",
6116
- this.namespacePath(`applications/${encodeURIComponent(applicationName)}`),
6117
- { statusOnlyCodes: /* @__PURE__ */ new Set([404]) }
6118
- );
6119
- if (response.status === 404) {
6120
- return void 0;
6121
- }
6122
- const application = await parseJsonResponse(response);
6123
- return publicEndpointIdFromManifest(application);
6124
- }
6125
- platformProjectPath(resource, organizationId, projectId) {
6126
- const resolvedOrganizationId = organizationId ?? this.organizationId;
6127
- const resolvedProjectId = projectId ?? this.projectId;
6128
- if (!resolvedOrganizationId && !resolvedProjectId) {
6129
- return `/platform/v1/${resource}`;
6130
- }
6131
- if (!resolvedOrganizationId || !resolvedProjectId) {
6132
- throw new Error(
6133
- "organizationId and projectId must be provided together"
6134
- );
6135
- }
6136
- return `/platform/v1/organizations/${encodeURIComponent(resolvedOrganizationId)}/projects/${encodeURIComponent(resolvedProjectId)}/${resource}`;
6137
- }
6138
- secretCollectionPath(organizationId, projectId) {
6139
- const resolvedOrganizationId = organizationId ?? this.organizationId;
6140
- const resolvedProjectId = projectId ?? this.projectId;
6141
- if (!resolvedOrganizationId && !resolvedProjectId) {
6142
- return this.namespacePath("secrets");
6143
- }
6144
- if (!resolvedOrganizationId || !resolvedProjectId) {
6145
- throw new Error("organizationId and projectId must be provided together");
6146
- }
6147
- return this.namespacePath("secrets");
6148
- }
6149
- };
6150
- UNAUTHENTICATED_REQUESTS = "unauthenticated_requests";
6151
- }
6152
- });
6153
-
6154
- // src/image.ts
6155
- function cloneOperation(op) {
6156
- return {
6157
- type: op.type,
6158
- args: [...op.args],
6159
- options: { ...op.options }
6160
- };
6161
- }
6162
- function renderOptions(options) {
6163
- const entries = Object.entries(options);
6164
- if (entries.length === 0) {
6165
- return "";
6166
- }
6167
- return ` ${entries.map(([key, value]) => `--${key}=${value}`).join(" ")}`;
6168
- }
6169
- function renderBuildOp(op) {
6170
- const options = renderOptions(op.options);
6171
- if (op.type === ImageBuildOperationType.ENV) {
6172
- return `ENV${options} ${op.args[0]}=${JSON.stringify(op.args[1])}`;
6173
- }
6174
- return `${op.type}${options} ${op.args.join(" ")}`;
6175
- }
6176
- function dockerfileContent(image) {
6177
- const lines = image.baseImage == null ? [] : [`FROM ${image.baseImage}`];
6178
- lines.push(...image.buildOperations.map((op) => renderBuildOp(op)));
6179
- return lines.join("\n");
6180
- }
6181
- var import_node_crypto, DEFAULT_IMAGE_NAME, ImageBuildOperationType, Image;
6182
- var init_image = __esm({
6183
- "src/image.ts"() {
6184
- "use strict";
6185
- init_cjs_shims();
6186
- import_node_crypto = require("crypto");
6187
- DEFAULT_IMAGE_NAME = "default";
6188
- ImageBuildOperationType = {
6189
- ADD: "ADD",
6190
- COPY: "COPY",
6191
- ENV: "ENV",
6192
- RUN: "RUN",
6193
- WORKDIR: "WORKDIR"
6194
- };
6195
- Image = class {
6196
- _id;
6197
- _name;
6198
- _tag;
6199
- _baseImage;
6200
- _buildOperations;
6201
- constructor(nameOrOptions = {}, tag = "latest", baseImage = null) {
6202
- this._id = (0, import_node_crypto.randomUUID)();
6203
- this._buildOperations = [];
6204
- if (typeof nameOrOptions === "string") {
6205
- this._name = nameOrOptions;
6206
- this._tag = tag;
6207
- this._baseImage = baseImage;
6208
- return;
6209
- }
6210
- this._name = nameOrOptions.name ?? DEFAULT_IMAGE_NAME;
6211
- this._tag = nameOrOptions.tag ?? "latest";
6212
- this._baseImage = nameOrOptions.baseImage ?? null;
6213
- }
6214
- get name() {
6215
- return this._name;
6216
- }
6217
- get tag() {
6218
- return this._tag;
6219
- }
6220
- get baseImage() {
6221
- return this._baseImage;
6222
- }
6223
- get buildOperations() {
6224
- return this._buildOperations.map(cloneOperation);
6225
- }
6226
- add(src, dest, options = void 0) {
6227
- return this._addOperation({
6228
- type: ImageBuildOperationType.ADD,
6229
- args: [src, dest],
6230
- options: options == null ? {} : { ...options }
6231
- });
6232
- }
6233
- copy(src, dest, options = void 0) {
6234
- return this._addOperation({
6235
- type: ImageBuildOperationType.COPY,
6236
- args: [src, dest],
6237
- options: options == null ? {} : { ...options }
6238
- });
6239
- }
6240
- env(key, value) {
6241
- return this._addOperation({
6242
- type: ImageBuildOperationType.ENV,
6243
- args: [key, value],
6244
- options: {}
6245
- });
6246
- }
6247
- run(commands, options = void 0) {
6248
- return this._addOperation({
6249
- type: ImageBuildOperationType.RUN,
6250
- args: Array.isArray(commands) ? [...commands] : [commands],
6251
- options: options == null ? {} : { ...options }
6252
- });
6253
- }
6254
- workdir(directory) {
6255
- return this._addOperation({
6256
- type: ImageBuildOperationType.WORKDIR,
6257
- args: [directory],
6258
- options: {}
6259
- });
6260
- }
6261
- /**
6262
- * Build this image as a sandbox template and register it.
5722
+ * Build this image as a sandbox template and register it.
6263
5723
  *
6264
5724
  * Materializes the image in a build sandbox, snapshots the filesystem,
6265
5725
  * and registers the snapshot as a named sandbox template.
@@ -6343,9 +5803,9 @@ var require_libc = __commonJS({
6343
5803
  // src/native-binding.ts
6344
5804
  function packageRoot() {
6345
5805
  const parent = (0, import_node_url.fileURLToPath)(new URL("../", importMetaUrl));
6346
- if (fs.existsSync(import_node_path2.default.join(parent, "package.json"))) return parent;
5806
+ if (fs.existsSync(import_node_path.default.join(parent, "package.json"))) return parent;
6347
5807
  const grandparent = (0, import_node_url.fileURLToPath)(new URL("../../", importMetaUrl));
6348
- if (fs.existsSync(import_node_path2.default.join(grandparent, "package.json"))) return grandparent;
5808
+ if (fs.existsSync(import_node_path.default.join(grandparent, "package.json"))) return grandparent;
6349
5809
  return parent;
6350
5810
  }
6351
5811
  function linuxLibcFamily(options) {
@@ -6368,7 +5828,7 @@ function nativeTargetId(platform = process.platform, arch = process.arch, option
6368
5828
  function nativeBindingPath(options = {}) {
6369
5829
  const platform = options.platform ?? process.platform;
6370
5830
  const arch = options.arch ?? process.arch;
6371
- return import_node_path2.default.join(
5831
+ return import_node_path.default.join(
6372
5832
  options.packageRoot ?? packageRoot(),
6373
5833
  "dist",
6374
5834
  "native",
@@ -6401,7 +5861,7 @@ function loadNative() {
6401
5861
  }
6402
5862
  return require2(packageEntry);
6403
5863
  }
6404
- var import_libc, fs, import_node_module2, import_node_path2, import_node_url, NATIVE_PACKAGES, cachedLinuxLibc;
5864
+ var import_libc, fs, import_node_module2, import_node_path, import_node_url, NATIVE_PACKAGES, cachedLinuxLibc;
6405
5865
  var init_native_binding = __esm({
6406
5866
  "src/native-binding.ts"() {
6407
5867
  "use strict";
@@ -6409,7 +5869,7 @@ var init_native_binding = __esm({
6409
5869
  import_libc = __toESM(require_libc(), 1);
6410
5870
  fs = __toESM(require("fs"), 1);
6411
5871
  import_node_module2 = require("module");
6412
- import_node_path2 = __toESM(require("path"), 1);
5872
+ import_node_path = __toESM(require("path"), 1);
6413
5873
  import_node_url = require("url");
6414
5874
  NATIVE_PACKAGES = {
6415
5875
  "darwin-arm64": "@tensorlakeai/native-darwin-arm64",
@@ -6422,16 +5882,562 @@ var init_native_binding = __esm({
6422
5882
  }
6423
5883
  });
6424
5884
 
5885
+ // src/image-builds.ts
5886
+ function isConfirmedCancellation(outcome) {
5887
+ return outcome === "cancelled" /* CANCELLED */ || outcome === "already_cancelled" /* ALREADY_CANCELLED */ || outcome === "already_failed" /* ALREADY_FAILED */;
5888
+ }
5889
+ function camelize(key) {
5890
+ return key.replace(/_([a-z])/g, (_, c) => c.toUpperCase());
5891
+ }
5892
+ function toImageBuildError(error) {
5893
+ if (!(error instanceof Error)) return error;
5894
+ let payload;
5895
+ try {
5896
+ payload = JSON.parse(error.message);
5897
+ } catch {
5898
+ return error;
5899
+ }
5900
+ if (!payload || payload.category !== "image_build") return error;
5901
+ const details = {};
5902
+ for (const [key, value] of Object.entries(payload)) {
5903
+ if (key === "category") continue;
5904
+ details[camelize(key)] = value;
5905
+ }
5906
+ details.code = enumValue(ImageBuildErrorCode, details.code || "internal" /* INTERNAL */);
5907
+ if ("activeKind" in details) details.activeKind = details.activeKind ? enumValue(ImageBuildKind, details.activeKind) : null;
5908
+ if ("activeStatus" in details) details.activeStatus = details.activeStatus ? enumValue(ImageBuildStatus, details.activeStatus) : null;
5909
+ if ("outcome" in details) details.outcome = details.outcome ? enumValue(ImageBuildCancellationOutcome, details.outcome) : null;
5910
+ if ("info" in details) details.info = buildInfoOrNull(details.info);
5911
+ const typed = details;
5912
+ const errors = {
5913
+ not_found: ImageBuildNotFoundError,
5914
+ image_build_in_progress: ImageBuildInProgressError,
5915
+ failed: ImageBuildFailedError,
5916
+ cancelled: ImageBuildCancelledError,
5917
+ timeout: ImageBuildTimeoutError,
5918
+ interrupted: ImageBuildInterruptedError
5919
+ };
5920
+ const ErrorClass = errors[typed.code] ?? ImageBuildError;
5921
+ return withRaw(new ErrorClass(typed), payload);
5922
+ }
5923
+ function camelizeRecord(value) {
5924
+ const out = {};
5925
+ for (const [key, inner] of Object.entries(value)) out[camelize(key)] = inner;
5926
+ return out;
5927
+ }
5928
+ function buildInfoOrNull(value) {
5929
+ if (!value || typeof value !== "object" || Array.isArray(value)) return null;
5930
+ try {
5931
+ return parseBuildInfo(value);
5932
+ } catch (error) {
5933
+ if (error instanceof ImageBuildError) return null;
5934
+ throw error;
5935
+ }
5936
+ }
5937
+ function decodeResponse(value) {
5938
+ try {
5939
+ const raw = typeof value === "string" ? JSON.parse(value) : value;
5940
+ if (!raw || typeof raw !== "object" || Array.isArray(raw)) throw new TypeError("expected a response object");
5941
+ return raw;
5942
+ } catch (error) {
5943
+ throw withRaw(new ImageBuildError({ code: "service" /* SERVICE */, message: `Invalid image-build response: ${String(error)}` }), { response: value });
5944
+ }
5945
+ }
5946
+ function parseBuildInfo(value) {
5947
+ const raw = decodeResponse(value);
5948
+ if (raw.status == null) {
5949
+ throw withRaw(new ImageBuildError({ code: "service" /* SERVICE */, message: "Invalid image-build response: missing status" }), { response: value });
5950
+ }
5951
+ const attempt = raw.attempt_no ?? 0;
5952
+ const attemptNo = Number(attempt);
5953
+ if (typeof attempt !== "number" && typeof attempt !== "string" || typeof attempt === "string" && attempt.trim() === "" || !Number.isSafeInteger(attemptNo)) {
5954
+ throw withRaw(new ImageBuildError({ code: "service" /* SERVICE */, message: "Invalid image-build attempt_no" }), { response: value });
5955
+ }
5956
+ const camel = camelizeRecord(raw);
5957
+ const result = raw.result && typeof raw.result === "object" ? camelizeRecord(raw.result) : null;
5958
+ return withRaw({
5959
+ buildId: String(raw.build_id ?? ""),
5960
+ clientRequestId: camel.clientRequestId ?? null,
5961
+ kind: raw.kind ? enumValue(ImageBuildKind, raw.kind) : null,
5962
+ name: raw.name ?? null,
5963
+ status: enumValue(ImageBuildStatus, raw.status),
5964
+ phase: raw.phase ? enumValue(ImageBuildPhase, raw.phase) : null,
5965
+ attemptNo,
5966
+ builderSandboxId: camel.builderSandboxId ?? null,
5967
+ error: raw.error ?? null,
5968
+ result,
5969
+ operationDeadlineMs: camel.operationDeadlineMs ?? null,
5970
+ createdAtMs: camel.createdAtMs ?? null,
5971
+ updatedAtMs: camel.updatedAtMs ?? null
5972
+ }, raw);
5973
+ }
5974
+ function parseResult(json) {
5975
+ return camelizeRecord(decodeResponse(json));
5976
+ }
5977
+ function credentialsFromEnv() {
5978
+ const context = __imageBuildInternals.buildContextFromEnv();
5979
+ if (!context.apiKey) {
5980
+ if (context.personalAccessToken) {
5981
+ throw new ImageBuildError({
5982
+ code: "auth" /* AUTH */,
5983
+ message: "Sandbox image SDKs require TENSORLAKE_API_KEY. Personal access tokens are CLI-only."
5984
+ });
5985
+ }
5986
+ throw new ImageBuildError({ code: "auth" /* AUTH */, message: "Missing TENSORLAKE_API_KEY credentials." });
5987
+ }
5988
+ return { apiUrl: context.apiUrl, bearerToken: context.apiKey, namespace: context.namespace };
5989
+ }
5990
+ function clientOptions(credentials) {
5991
+ return {
5992
+ apiUrl: credentials.apiUrl,
5993
+ bearerToken: credentials.bearerToken,
5994
+ namespace: credentials.namespace,
5995
+ useScopeHeaders: false
5996
+ };
5997
+ }
5998
+ function rejectLegacyReference(buildId) {
5999
+ if (typeof buildId !== "string" || buildId.trim().length === 0) {
6000
+ throw new ImageBuildError({ code: "usage" /* USAGE */, message: "buildId must be a non-empty string" });
6001
+ }
6002
+ if (buildId.startsWith("sandbox_template_")) {
6003
+ throw new ImageBuildError({
6004
+ code: "usage" /* USAGE */,
6005
+ message: `'${buildId}' is a legacy sandbox template id; legacy images have no build operation to get, wait for or cancel`,
6006
+ buildId
6007
+ });
6008
+ }
6009
+ if (buildId.startsWith("image_")) {
6010
+ throw new ImageBuildError({
6011
+ code: "usage" /* USAGE */,
6012
+ message: `'${buildId}' is an image id, not a build id; look the image up with findSandboxImageByName or use the build id admission returned`,
6013
+ buildId
6014
+ });
6015
+ }
6016
+ }
6017
+ async function __runWithInterrupt(signal, run) {
6018
+ const binding = __imageBuildInternals.loadNativeBinding();
6019
+ if (signal === void 0) {
6020
+ try {
6021
+ return await run(void 0);
6022
+ } catch (error) {
6023
+ throw toImageBuildError(error);
6024
+ }
6025
+ }
6026
+ const interruptId = binding.createImageBuildInterrupt();
6027
+ const onAbort = () => binding.triggerImageBuildInterrupt(interruptId);
6028
+ if (signal.aborted) onAbort();
6029
+ else signal.addEventListener("abort", onAbort, { once: true });
6030
+ try {
6031
+ return await run(interruptId);
6032
+ } catch (error) {
6033
+ throw toImageBuildError(error);
6034
+ } finally {
6035
+ signal.removeEventListener("abort", onAbort);
6036
+ binding.releaseImageBuildInterrupt(interruptId);
6037
+ }
6038
+ }
6039
+ function makeEmitter(options) {
6040
+ const emit = options.emit ?? (options.verbose ? __imageBuildInternals.stderrEmit : __imageBuildInternals.noopEmit);
6041
+ let emitError;
6042
+ const forward = (event) => {
6043
+ try {
6044
+ emit(__imageBuildInternals.eventToEmitDict(event));
6045
+ } catch (error) {
6046
+ emitError ??= error;
6047
+ }
6048
+ };
6049
+ return {
6050
+ forward,
6051
+ emit,
6052
+ rethrow() {
6053
+ if (emitError != null) throw emitError;
6054
+ }
6055
+ };
6056
+ }
6057
+ function decodeStarted(json, credentials) {
6058
+ const payload = decodeResponse(json);
6059
+ const build = payload.build;
6060
+ if (!build || typeof build !== "object" || Array.isArray(build) || typeof build.build_id !== "string" || !build.build_id.trim()) {
6061
+ throw withRaw(new ImageBuildError({
6062
+ code: "service" /* SERVICE */,
6063
+ message: "Invalid image-build admission: expected a build with a non-empty build_id"
6064
+ }), { response: payload });
6065
+ }
6066
+ return new ImageBuildHandle(parseBuildInfo(build), credentials, payload.client_request_id);
6067
+ }
6068
+ async function startImageBuild(source, options = {}, deps = {}) {
6069
+ const emitter = makeEmitter({ emit: deps.emit ?? options.emit, verbose: options.verbose });
6070
+ let dockerfilePath;
6071
+ let dockerfileText;
6072
+ let contextDir;
6073
+ let name;
6074
+ let tempContextDir;
6075
+ if (source instanceof Image) {
6076
+ if (!source.baseImage) throw new Error("Image must have a baseImage to build");
6077
+ if (options.contextDir != null) {
6078
+ contextDir = import_node_path2.default.resolve(options.contextDir);
6079
+ } else if (__imageBuildInternals.imageRequiresContext(source)) {
6080
+ throw new Error(
6081
+ "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>`."
6082
+ );
6083
+ } else {
6084
+ tempContextDir = (0, import_node_fs.mkdtempSync)(import_node_path2.default.join(import_node_os.default.tmpdir(), "tl-build-context-"));
6085
+ contextDir = tempContextDir;
6086
+ }
6087
+ dockerfilePath = import_node_path2.default.join(contextDir, "Dockerfile");
6088
+ let text = dockerfileContent(source);
6089
+ if (!text.endsWith("\n")) text += "\n";
6090
+ dockerfileText = text;
6091
+ name = options.registeredName ?? source.name;
6092
+ } else if (typeof source === "string") {
6093
+ const resolved = import_node_path2.default.resolve(source);
6094
+ if (!(0, import_node_fs.existsSync)(resolved)) throw new Error(`Dockerfile not found: ${source}`);
6095
+ dockerfilePath = resolved;
6096
+ name = options.registeredName ?? __imageBuildInternals.defaultRegisteredName(resolved);
6097
+ } else {
6098
+ throw new TypeError(`source must be an Image or a Dockerfile path, got ${typeof source}`);
6099
+ }
6100
+ try {
6101
+ const credentials = credentialsFromEnv();
6102
+ const binding = __imageBuildInternals.loadNativeBinding();
6103
+ emitter.emit({ type: "status", message: `Building image '${name}'...` });
6104
+ const json = await __runWithInterrupt(
6105
+ options.signal,
6106
+ (interruptId) => binding.startImageBuild(
6107
+ {
6108
+ apiUrl: credentials.apiUrl,
6109
+ bearerToken: credentials.bearerToken,
6110
+ dockerfilePath,
6111
+ registeredName: name,
6112
+ diskMb: options.diskMb,
6113
+ cpus: options.cpus,
6114
+ memoryMb: options.memoryMb,
6115
+ isPublic: options.isPublic ?? false,
6116
+ namespace: credentials.namespace,
6117
+ useScopeHeaders: false,
6118
+ dockerConfigJson: options.dockerConfigJson,
6119
+ dockerfileText,
6120
+ contextDir,
6121
+ cas: true,
6122
+ buildArgs: options.buildArgs
6123
+ },
6124
+ emitter.forward,
6125
+ interruptId
6126
+ )
6127
+ );
6128
+ emitter.rethrow();
6129
+ return decodeStarted(json, credentials);
6130
+ } finally {
6131
+ if (tempContextDir != null) (0, import_node_fs.rmSync)(tempContextDir, { recursive: true, force: true });
6132
+ }
6133
+ }
6134
+ async function startImageImport(imageReference, options = {}, deps = {}) {
6135
+ if (typeof imageReference !== "string" || imageReference.trim().length === 0) {
6136
+ throw new Error("image reference to import must not be empty");
6137
+ }
6138
+ const reference = imageReference.trim();
6139
+ const name = options.registeredName ?? __imageBuildInternals.defaultRegisteredNameFromImage(reference);
6140
+ const emitter = makeEmitter({ emit: deps.emit ?? options.emit, verbose: options.verbose });
6141
+ const credentials = credentialsFromEnv();
6142
+ const binding = __imageBuildInternals.loadNativeBinding();
6143
+ emitter.emit({ type: "status", message: `Importing image '${reference}' as '${name}'...` });
6144
+ const json = await __runWithInterrupt(
6145
+ options.signal,
6146
+ (interruptId) => binding.startImageImport(
6147
+ {
6148
+ apiUrl: credentials.apiUrl,
6149
+ bearerToken: credentials.bearerToken,
6150
+ imageReference: reference,
6151
+ registeredName: name,
6152
+ diskMb: options.diskMb,
6153
+ cpus: options.cpus,
6154
+ memoryMb: options.memoryMb,
6155
+ isPublic: options.isPublic ?? false,
6156
+ namespace: credentials.namespace,
6157
+ useScopeHeaders: false,
6158
+ dockerConfigJson: options.dockerConfigJson,
6159
+ cas: true
6160
+ },
6161
+ emitter.forward,
6162
+ interruptId
6163
+ )
6164
+ );
6165
+ emitter.rethrow();
6166
+ return decodeStarted(json, credentials);
6167
+ }
6168
+ async function getImageBuild(buildId) {
6169
+ rejectLegacyReference(buildId);
6170
+ const credentials = credentialsFromEnv();
6171
+ const binding = __imageBuildInternals.loadNativeBinding();
6172
+ let json;
6173
+ try {
6174
+ json = await binding.getImageBuild(clientOptions(credentials), buildId);
6175
+ } catch (error) {
6176
+ throw toImageBuildError(error);
6177
+ }
6178
+ return new ImageBuildHandle(parseBuildInfo(json), credentials);
6179
+ }
6180
+ async function waitImageBuild(buildId, options = {}) {
6181
+ rejectLegacyReference(buildId);
6182
+ const credentials = credentialsFromEnv();
6183
+ const binding = __imageBuildInternals.loadNativeBinding();
6184
+ const emitter = makeEmitter(options);
6185
+ const json = await __runWithInterrupt(
6186
+ options.signal,
6187
+ (interruptId) => binding.waitImageBuild(
6188
+ clientOptions(credentials),
6189
+ buildId,
6190
+ { timeoutMs: options.timeoutMs, followLogs: options.followLogs ?? false },
6191
+ emitter.forward,
6192
+ interruptId
6193
+ )
6194
+ );
6195
+ emitter.rethrow();
6196
+ return parseResult(json);
6197
+ }
6198
+ async function cancelImageBuildWith(credentials, selector) {
6199
+ const binding = __imageBuildInternals.loadNativeBinding();
6200
+ let json;
6201
+ try {
6202
+ json = await binding.cancelImageBuild(clientOptions(credentials), {
6203
+ buildId: selector.buildId,
6204
+ clientRequestId: selector.clientRequestId
6205
+ });
6206
+ } catch (error) {
6207
+ throw toImageBuildError(error);
6208
+ }
6209
+ const payload = decodeResponse(json);
6210
+ const outcome = enumValue(ImageBuildCancellationOutcome, payload.outcome);
6211
+ return withRaw({ outcome, build: buildInfoOrNull(payload.build), confirmed: isConfirmedCancellation(outcome) }, payload);
6212
+ }
6213
+ async function cancelImageBuild(selector) {
6214
+ const hasBuild = selector.buildId != null;
6215
+ const hasRequest = selector.clientRequestId != null;
6216
+ if (hasBuild === hasRequest) {
6217
+ throw new ImageBuildError({
6218
+ code: "usage" /* USAGE */,
6219
+ message: "pass exactly one of buildId or clientRequestId"
6220
+ });
6221
+ }
6222
+ if (selector.buildId != null) rejectLegacyReference(selector.buildId);
6223
+ return cancelImageBuildWith(credentialsFromEnv(), selector);
6224
+ }
6225
+ var import_node_path2, import_node_os, import_node_fs, ImageBuildStatus, ImageBuildPhase, ImageBuildKind, ImageBuildCancellationOutcome, ImageBuildErrorCode, ImageBuildError, ImageBuildNotFoundError, ImageBuildInProgressError, ImageBuildFailedError, ImageBuildCancelledError, ImageBuildTimeoutError, ImageBuildInterruptedError, ImageBuildHandle;
6226
+ var init_image_builds = __esm({
6227
+ "src/image-builds.ts"() {
6228
+ "use strict";
6229
+ init_cjs_shims();
6230
+ import_node_path2 = __toESM(require("path"), 1);
6231
+ init_enum();
6232
+ import_node_os = __toESM(require("os"), 1);
6233
+ import_node_fs = require("fs");
6234
+ init_image();
6235
+ init_sandbox_image();
6236
+ ImageBuildStatus = /* @__PURE__ */ ((ImageBuildStatus2) => {
6237
+ ImageBuildStatus2["PENDING"] = "pending";
6238
+ ImageBuildStatus2["RUNNING"] = "running";
6239
+ ImageBuildStatus2["SUCCEEDED"] = "succeeded";
6240
+ ImageBuildStatus2["FAILED"] = "failed";
6241
+ ImageBuildStatus2["CANCELLED"] = "cancelled";
6242
+ ImageBuildStatus2["UNKNOWN"] = "unknown";
6243
+ return ImageBuildStatus2;
6244
+ })(ImageBuildStatus || {});
6245
+ ImageBuildPhase = /* @__PURE__ */ ((ImageBuildPhase2) => {
6246
+ ImageBuildPhase2["AWAITING_CONTEXT"] = "awaiting_context";
6247
+ ImageBuildPhase2["STARTING_BUILDER"] = "starting_builder";
6248
+ ImageBuildPhase2["EXECUTING"] = "executing";
6249
+ ImageBuildPhase2["SNAPSHOTTING"] = "snapshotting";
6250
+ ImageBuildPhase2["PUBLISHING"] = "publishing";
6251
+ ImageBuildPhase2["FINISHED"] = "finished";
6252
+ ImageBuildPhase2["UNKNOWN"] = "unknown";
6253
+ return ImageBuildPhase2;
6254
+ })(ImageBuildPhase || {});
6255
+ ImageBuildKind = /* @__PURE__ */ ((ImageBuildKind2) => {
6256
+ ImageBuildKind2["DOCKERFILE"] = "dockerfile";
6257
+ ImageBuildKind2["IMPORT"] = "import";
6258
+ ImageBuildKind2["DIRECT"] = "direct";
6259
+ ImageBuildKind2["UNKNOWN"] = "unknown";
6260
+ return ImageBuildKind2;
6261
+ })(ImageBuildKind || {});
6262
+ ImageBuildCancellationOutcome = /* @__PURE__ */ ((ImageBuildCancellationOutcome2) => {
6263
+ ImageBuildCancellationOutcome2["CANCELLED"] = "cancelled";
6264
+ ImageBuildCancellationOutcome2["ALREADY_CANCELLED"] = "already_cancelled";
6265
+ ImageBuildCancellationOutcome2["ALREADY_COMPLETED"] = "already_completed";
6266
+ ImageBuildCancellationOutcome2["ALREADY_FAILED"] = "already_failed";
6267
+ ImageBuildCancellationOutcome2["NOT_ADMITTED"] = "not_admitted";
6268
+ ImageBuildCancellationOutcome2["UNCONFIRMED"] = "unconfirmed";
6269
+ ImageBuildCancellationOutcome2["UNKNOWN"] = "unknown";
6270
+ return ImageBuildCancellationOutcome2;
6271
+ })(ImageBuildCancellationOutcome || {});
6272
+ ImageBuildErrorCode = /* @__PURE__ */ ((ImageBuildErrorCode2) => {
6273
+ ImageBuildErrorCode2["USAGE"] = "usage";
6274
+ ImageBuildErrorCode2["AUTH"] = "auth";
6275
+ ImageBuildErrorCode2["NOT_FOUND"] = "not_found";
6276
+ ImageBuildErrorCode2["IMAGE_BUILD_IN_PROGRESS"] = "image_build_in_progress";
6277
+ ImageBuildErrorCode2["CLIENT_REQUEST_ID_MISMATCH"] = "client_request_id_mismatch";
6278
+ ImageBuildErrorCode2["FAILED"] = "failed";
6279
+ ImageBuildErrorCode2["CANCELLED"] = "cancelled";
6280
+ ImageBuildErrorCode2["TIMEOUT"] = "timeout";
6281
+ ImageBuildErrorCode2["INTERRUPTED"] = "interrupted";
6282
+ ImageBuildErrorCode2["SERVICE"] = "service";
6283
+ ImageBuildErrorCode2["INTERNAL"] = "internal";
6284
+ ImageBuildErrorCode2["UNKNOWN"] = "unknown";
6285
+ return ImageBuildErrorCode2;
6286
+ })(ImageBuildErrorCode || {});
6287
+ ImageBuildError = class extends Error {
6288
+ code;
6289
+ buildId;
6290
+ clientRequestId;
6291
+ details;
6292
+ constructor(details) {
6293
+ super(details.message);
6294
+ this.name = "ImageBuildError";
6295
+ this.code = details.code;
6296
+ this.details = { ...details };
6297
+ withRaw(this, {});
6298
+ if ("confirmed" in details) {
6299
+ this.details.confirmed = details.confirmed === true && isConfirmedCancellation(details.outcome);
6300
+ }
6301
+ if (details.buildId) this.buildId = details.buildId;
6302
+ if (details.clientRequestId) this.clientRequestId = details.clientRequestId;
6303
+ }
6304
+ };
6305
+ ImageBuildNotFoundError = class extends ImageBuildError {
6306
+ constructor(details) {
6307
+ super(details);
6308
+ this.name = "ImageBuildNotFoundError";
6309
+ }
6310
+ };
6311
+ ImageBuildInProgressError = class extends ImageBuildError {
6312
+ imageName;
6313
+ activeBuildId;
6314
+ activeKind;
6315
+ activeStatus;
6316
+ constructor(details) {
6317
+ super(details);
6318
+ this.name = "ImageBuildInProgressError";
6319
+ if (details.imageName) this.imageName = details.imageName;
6320
+ if (details.activeBuildId) this.activeBuildId = details.activeBuildId;
6321
+ if (details.activeKind) this.activeKind = details.activeKind;
6322
+ if (details.activeStatus) this.activeStatus = details.activeStatus;
6323
+ }
6324
+ };
6325
+ ImageBuildFailedError = class extends ImageBuildError {
6326
+ error;
6327
+ info;
6328
+ constructor(details) {
6329
+ super(details);
6330
+ this.name = "ImageBuildFailedError";
6331
+ this.error = details.error ?? "no error recorded";
6332
+ if (details.info) this.info = details.info;
6333
+ }
6334
+ };
6335
+ ImageBuildCancelledError = class extends ImageBuildError {
6336
+ info;
6337
+ constructor(details) {
6338
+ super(details);
6339
+ this.name = "ImageBuildCancelledError";
6340
+ if (details.info) this.info = details.info;
6341
+ }
6342
+ };
6343
+ ImageBuildTimeoutError = class extends ImageBuildError {
6344
+ constructor(details) {
6345
+ super(details);
6346
+ this.name = "ImageBuildTimeoutError";
6347
+ }
6348
+ };
6349
+ ImageBuildInterruptedError = class extends ImageBuildError {
6350
+ outcome;
6351
+ confirmed;
6352
+ result;
6353
+ constructor(details) {
6354
+ super(details);
6355
+ this.name = "ImageBuildInterruptedError";
6356
+ this.outcome = details.outcome ?? "unconfirmed" /* UNCONFIRMED */;
6357
+ this.confirmed = this.details.confirmed === true;
6358
+ if (details.result) this.result = details.result;
6359
+ }
6360
+ };
6361
+ ImageBuildHandle = class {
6362
+ buildId;
6363
+ /**
6364
+ * The admission's request id, when this handle started the build. Never
6365
+ * needed to cancel; a recovery aid for a lost admission answer.
6366
+ */
6367
+ clientRequestId;
6368
+ #info;
6369
+ #credentials;
6370
+ /** @internal */
6371
+ constructor(info, credentials, clientRequestId) {
6372
+ this.buildId = info.buildId;
6373
+ this.clientRequestId = clientRequestId ?? info.clientRequestId ?? null;
6374
+ this.#info = info;
6375
+ this.#credentials = credentials;
6376
+ }
6377
+ /** The last observed state. */
6378
+ get info() {
6379
+ return this.#info;
6380
+ }
6381
+ /** Re-read the current state. */
6382
+ async refresh() {
6383
+ const binding = __imageBuildInternals.loadNativeBinding();
6384
+ let json;
6385
+ try {
6386
+ json = await binding.getImageBuild(clientOptions(this.#credentials), this.buildId);
6387
+ } catch (error) {
6388
+ throw toImageBuildError(error);
6389
+ }
6390
+ this.#info = parseBuildInfo(json);
6391
+ return this.#info;
6392
+ }
6393
+ /**
6394
+ * Wait for publication and return this build's immutable result. See
6395
+ * {@link ImageBuildWaitOptions} for the timeout/abort distinction.
6396
+ */
6397
+ async wait(options = {}) {
6398
+ const binding = __imageBuildInternals.loadNativeBinding();
6399
+ const emitter = makeEmitter(options);
6400
+ const json = await __runWithInterrupt(
6401
+ options.signal,
6402
+ (interruptId) => binding.waitImageBuild(
6403
+ clientOptions(this.#credentials),
6404
+ this.buildId,
6405
+ { timeoutMs: options.timeoutMs, followLogs: options.followLogs ?? false },
6406
+ emitter.forward,
6407
+ interruptId
6408
+ )
6409
+ );
6410
+ emitter.rethrow();
6411
+ const raw = decodeResponse(json);
6412
+ const result = camelizeRecord(raw);
6413
+ this.#info = withRaw(
6414
+ { ...this.#info, status: "succeeded" /* SUCCEEDED */, result },
6415
+ { ...this.#info.raw, status: "succeeded", result: raw }
6416
+ );
6417
+ return result;
6418
+ }
6419
+ /** Cancel this build by its id (the sufficient selector). */
6420
+ async cancel() {
6421
+ return cancelImageBuildWith(this.#credentials, { buildId: this.buildId });
6422
+ }
6423
+ };
6424
+ }
6425
+ });
6426
+
6425
6427
  // src/sandbox-image.ts
6426
6428
  var sandbox_image_exports = {};
6427
6429
  __export(sandbox_image_exports, {
6430
+ __imageBuildInternals: () => __imageBuildInternals,
6428
6431
  __setNativeBindingForTest: () => __setNativeBindingForTest,
6429
6432
  buildContextFromEnv: () => buildContextFromEnv,
6430
6433
  createSandboxImage: () => createSandboxImage,
6431
6434
  deleteSandboxImage: () => deleteSandboxImage,
6435
+ deleteSandboxImageWithCredentials: () => deleteSandboxImageWithCredentials,
6432
6436
  findSandboxImageByName: () => findSandboxImageByName,
6437
+ findSandboxImageByNameWithCredentials: () => findSandboxImageByNameWithCredentials,
6433
6438
  importSandboxImage: () => importSandboxImage,
6434
6439
  listSandboxImages: () => listSandboxImages,
6440
+ listSandboxImagesWithCredentials: () => listSandboxImagesWithCredentials,
6435
6441
  runCreateSandboxImageCli: () => runCreateSandboxImageCli,
6436
6442
  runImportSandboxImageCli: () => runImportSandboxImageCli
6437
6443
  });
@@ -6505,6 +6511,15 @@ function eventToEmitDict(event) {
6505
6511
  message: event.message
6506
6512
  };
6507
6513
  if (event.stream != null) out.stream = event.stream;
6514
+ if (event.buildId != null) out.build_id = event.buildId;
6515
+ if (event.clientRequestId !== void 0 && event.eventType !== "status") {
6516
+ out.client_request_id = event.clientRequestId;
6517
+ }
6518
+ if (event.status != null) out.status = event.status;
6519
+ if (event.phase !== void 0 && event.eventType.startsWith("build_")) out.phase = event.phase;
6520
+ if (event.attempt != null) out.attempt = event.attempt;
6521
+ if (event.outcome != null) out.outcome = event.outcome;
6522
+ if (event.confirmed != null) out.confirmed = event.confirmed;
6508
6523
  return out;
6509
6524
  }
6510
6525
  function runOpMountsContext(op) {
@@ -6606,38 +6621,47 @@ async function createSandboxImage(source, options = {}, deps = {}) {
6606
6621
  deps._allowPat ? "Missing TENSORLAKE_API_KEY or TENSORLAKE_PAT credentials." : "Missing TENSORLAKE_API_KEY credentials."
6607
6622
  );
6608
6623
  }
6624
+ if (options.signal !== void 0 && !options.cas) {
6625
+ throw new Error(
6626
+ "signal is only supported for CAS image builds (cas: true); a legacy build has no Image Service build operation to cancel"
6627
+ );
6628
+ }
6609
6629
  emit({ type: "status", message: `Building image '${effectiveName}'...` });
6610
6630
  const binding = loadNativeBinding();
6611
6631
  let emitError;
6612
- const resultJson = await binding.buildSandboxImage(
6613
- {
6614
- apiUrl: context.apiUrl,
6615
- bearerToken,
6616
- dockerfilePath,
6617
- registeredName: effectiveName,
6618
- diskMb: options.diskMb,
6619
- builderDiskMb: options.builderDiskMb,
6620
- cpus: options.cpus,
6621
- memoryMb: options.memoryMb,
6622
- isPublic: options.isPublic ?? false,
6623
- organizationId: usePat ? context.organizationId : void 0,
6624
- projectId: usePat ? context.projectId : void 0,
6625
- namespace: context.namespace,
6626
- useScopeHeaders: usePat,
6627
- userAgent: void 0,
6628
- dockerCompat: options.dockerCompat ?? false,
6629
- dockerConfigJson: options.dockerConfigJson,
6630
- dockerfileText,
6631
- contextDir: nativeContextDir
6632
- },
6633
- (event) => {
6634
- try {
6635
- emit(eventToEmitDict(event));
6636
- } catch (error) {
6637
- emitError ??= error;
6638
- }
6632
+ const nativeOptions = {
6633
+ apiUrl: context.apiUrl,
6634
+ bearerToken,
6635
+ dockerfilePath,
6636
+ registeredName: effectiveName,
6637
+ diskMb: options.diskMb,
6638
+ builderDiskMb: options.builderDiskMb,
6639
+ cpus: options.cpus,
6640
+ memoryMb: options.memoryMb,
6641
+ isPublic: options.isPublic ?? false,
6642
+ organizationId: usePat ? context.organizationId : void 0,
6643
+ projectId: usePat ? context.projectId : void 0,
6644
+ namespace: context.namespace,
6645
+ useScopeHeaders: usePat,
6646
+ userAgent: void 0,
6647
+ dockerCompat: options.dockerCompat ?? false,
6648
+ dockerConfigJson: options.dockerConfigJson,
6649
+ dockerfileText,
6650
+ contextDir: nativeContextDir,
6651
+ cas: options.cas ?? false,
6652
+ buildArgs: options.buildArgs
6653
+ };
6654
+ const forward = (event) => {
6655
+ try {
6656
+ emit(eventToEmitDict(event));
6657
+ } catch (error) {
6658
+ emitError ??= error;
6639
6659
  }
6640
- );
6660
+ };
6661
+ const resultJson = options.cas ? await __runWithInterrupt(
6662
+ options.signal,
6663
+ (interruptId) => binding.buildSandboxImage(nativeOptions, forward, interruptId)
6664
+ ) : await binding.buildSandboxImage(nativeOptions, forward);
6641
6665
  if (emitError != null) {
6642
6666
  throw emitError;
6643
6667
  }
@@ -6683,39 +6707,47 @@ async function importSandboxImage(imageReference, options = {}, deps = {}) {
6683
6707
  deps._allowPat ? "Missing TENSORLAKE_API_KEY or TENSORLAKE_PAT credentials." : "Missing TENSORLAKE_API_KEY credentials."
6684
6708
  );
6685
6709
  }
6710
+ if (options.signal !== void 0 && !options.cas) {
6711
+ throw new Error(
6712
+ "signal is only supported for CAS image imports (cas: true); a legacy import has no Image Service build operation to cancel"
6713
+ );
6714
+ }
6686
6715
  emit({
6687
6716
  type: "status",
6688
6717
  message: `Importing image '${reference}' as '${effectiveName}'...`
6689
6718
  });
6690
6719
  const binding = loadNativeBinding();
6691
6720
  let emitError;
6692
- const resultJson = await binding.importSandboxImage(
6693
- {
6694
- apiUrl: context.apiUrl,
6695
- bearerToken,
6696
- imageReference: reference,
6697
- registeredName: effectiveName,
6698
- diskMb: options.diskMb,
6699
- builderDiskMb: options.builderDiskMb,
6700
- cpus: options.cpus,
6701
- memoryMb: options.memoryMb,
6702
- isPublic: options.isPublic ?? false,
6703
- organizationId: usePat ? context.organizationId : void 0,
6704
- projectId: usePat ? context.projectId : void 0,
6705
- namespace: context.namespace,
6706
- useScopeHeaders: usePat,
6707
- userAgent: void 0,
6708
- dockerCompat: options.dockerCompat ?? false,
6709
- dockerConfigJson: options.dockerConfigJson
6710
- },
6711
- (event) => {
6712
- try {
6713
- emit(eventToEmitDict(event));
6714
- } catch (error) {
6715
- emitError ??= error;
6716
- }
6721
+ const nativeOptions = {
6722
+ apiUrl: context.apiUrl,
6723
+ bearerToken,
6724
+ imageReference: reference,
6725
+ registeredName: effectiveName,
6726
+ diskMb: options.diskMb,
6727
+ builderDiskMb: options.builderDiskMb,
6728
+ cpus: options.cpus,
6729
+ memoryMb: options.memoryMb,
6730
+ isPublic: options.isPublic ?? false,
6731
+ organizationId: usePat ? context.organizationId : void 0,
6732
+ projectId: usePat ? context.projectId : void 0,
6733
+ namespace: context.namespace,
6734
+ useScopeHeaders: usePat,
6735
+ userAgent: void 0,
6736
+ dockerCompat: options.dockerCompat ?? false,
6737
+ dockerConfigJson: options.dockerConfigJson,
6738
+ cas: options.cas ?? false
6739
+ };
6740
+ const forward = (event) => {
6741
+ try {
6742
+ emit(eventToEmitDict(event));
6743
+ } catch (error) {
6744
+ emitError ??= error;
6717
6745
  }
6718
- );
6746
+ };
6747
+ const resultJson = options.cas ? await __runWithInterrupt(
6748
+ options.signal,
6749
+ (interruptId) => binding.importSandboxImage(nativeOptions, forward, interruptId)
6750
+ ) : await binding.importSandboxImage(nativeOptions, forward);
6719
6751
  if (emitError != null) {
6720
6752
  throw emitError;
6721
6753
  }
@@ -6731,10 +6763,7 @@ async function importSandboxImage(imageReference, options = {}, deps = {}) {
6731
6763
  emit({ type: "done" });
6732
6764
  return result;
6733
6765
  }
6734
- async function deleteSandboxImage(imageName) {
6735
- if (typeof imageName !== "string" || imageName.length === 0) {
6736
- throw new TypeError("imageName must be a non-empty string");
6737
- }
6766
+ function catalogOptionsFromEnv() {
6738
6767
  const context = buildContextFromEnv();
6739
6768
  const bearerToken = context.apiKey;
6740
6769
  if (!bearerToken) {
@@ -6745,66 +6774,76 @@ async function deleteSandboxImage(imageName) {
6745
6774
  }
6746
6775
  throw new Error("Missing TENSORLAKE_API_KEY credentials.");
6747
6776
  }
6748
- const client = new CloudClient({
6749
- apiUrl: context.apiUrl,
6750
- apiKey: bearerToken,
6751
- namespace: context.namespace
6752
- });
6753
- try {
6754
- await client.deleteSandboxImage(imageName);
6755
- } finally {
6756
- client.close();
6757
- }
6777
+ return { apiUrl: context.apiUrl, bearerToken, useScopeHeaders: false };
6758
6778
  }
6759
- async function findSandboxImageByName(imageName) {
6760
- if (typeof imageName !== "string" || imageName.length === 0) {
6761
- throw new TypeError("imageName must be a non-empty string");
6762
- }
6779
+ function catalogOptionsFromCredentials(credentials) {
6763
6780
  const context = buildContextFromEnv();
6764
- const bearerToken = context.apiKey;
6781
+ const bearerToken = credentials.apiKey ?? context.apiKey;
6765
6782
  if (!bearerToken) {
6766
- if (context.personalAccessToken) {
6767
- throw new Error(
6768
- "Sandbox image SDKs require TENSORLAKE_API_KEY. Personal access tokens are CLI-only."
6769
- );
6770
- }
6771
6783
  throw new Error("Missing TENSORLAKE_API_KEY credentials.");
6772
6784
  }
6773
- const client = new CloudClient({
6774
- apiUrl: context.apiUrl,
6775
- apiKey: bearerToken,
6776
- namespace: context.namespace
6777
- });
6778
- try {
6779
- return await client.findSandboxImageByName(imageName);
6780
- } finally {
6781
- client.close();
6785
+ const { organizationId, projectId } = credentials;
6786
+ if (organizationId === void 0 !== (projectId === void 0)) {
6787
+ throw new TypeError("organizationId and projectId must be given together");
6782
6788
  }
6789
+ return {
6790
+ apiUrl: credentials.apiUrl ?? context.apiUrl,
6791
+ bearerToken,
6792
+ organizationId,
6793
+ projectId,
6794
+ useScopeHeaders: organizationId !== void 0
6795
+ };
6783
6796
  }
6784
- async function listSandboxImages() {
6785
- const context = buildContextFromEnv();
6786
- const bearerToken = context.apiKey;
6787
- if (!bearerToken) {
6788
- if (context.personalAccessToken) {
6789
- throw new Error(
6790
- "Sandbox image SDKs require TENSORLAKE_API_KEY. Personal access tokens are CLI-only."
6791
- );
6792
- }
6793
- throw new Error("Missing TENSORLAKE_API_KEY credentials.");
6797
+ function parseTemplate(json) {
6798
+ return JSON.parse(json);
6799
+ }
6800
+ async function deleteSandboxImage(imageName) {
6801
+ if (typeof imageName !== "string" || imageName.length === 0) {
6802
+ throw new TypeError("imageName must be a non-empty string");
6794
6803
  }
6795
- const client = new CloudClient({
6796
- apiUrl: context.apiUrl,
6797
- apiKey: bearerToken,
6798
- namespace: context.namespace
6799
- });
6800
- try {
6801
- return await client.listSandboxImages();
6802
- } finally {
6803
- client.close();
6804
+ await loadNativeBinding().deleteSandboxImage(catalogOptionsFromEnv(), imageName);
6805
+ }
6806
+ async function deleteSandboxImageWithCredentials(credentials, imageName) {
6807
+ if (typeof imageName !== "string" || imageName.length === 0) {
6808
+ throw new TypeError("imageName must be a non-empty string");
6809
+ }
6810
+ await loadNativeBinding().deleteSandboxImage(
6811
+ catalogOptionsFromCredentials(credentials),
6812
+ imageName
6813
+ );
6814
+ }
6815
+ async function findSandboxImageByName(imageName) {
6816
+ if (typeof imageName !== "string" || imageName.length === 0) {
6817
+ throw new TypeError("imageName must be a non-empty string");
6818
+ }
6819
+ const json = await loadNativeBinding().findSandboxImage(
6820
+ catalogOptionsFromEnv(),
6821
+ imageName
6822
+ );
6823
+ return json == null ? null : parseTemplate(json);
6824
+ }
6825
+ async function findSandboxImageByNameWithCredentials(credentials, imageName) {
6826
+ if (typeof imageName !== "string" || imageName.length === 0) {
6827
+ throw new TypeError("imageName must be a non-empty string");
6804
6828
  }
6829
+ const json = await loadNativeBinding().findSandboxImage(
6830
+ catalogOptionsFromCredentials(credentials),
6831
+ imageName
6832
+ );
6833
+ return json == null ? null : parseTemplate(json);
6834
+ }
6835
+ async function listSandboxImages() {
6836
+ const json = await loadNativeBinding().listSandboxImages(catalogOptionsFromEnv());
6837
+ return JSON.parse(json);
6838
+ }
6839
+ async function listSandboxImagesWithCredentials(credentials) {
6840
+ const json = await loadNativeBinding().listSandboxImages(
6841
+ catalogOptionsFromCredentials(credentials)
6842
+ );
6843
+ return JSON.parse(json);
6805
6844
  }
6806
6845
  async function runCreateSandboxImageCli(argv = process.argv.slice(2)) {
6807
- const parsed = (0, import_node_util2.parseArgs)({
6846
+ const parsed = (0, import_node_util.parseArgs)({
6808
6847
  args: argv,
6809
6848
  allowPositionals: true,
6810
6849
  options: {
@@ -6858,7 +6897,7 @@ async function runCreateSandboxImageCli(argv = process.argv.slice(2)) {
6858
6897
  );
6859
6898
  }
6860
6899
  async function runImportSandboxImageCli(argv = process.argv.slice(2)) {
6861
- const parsed = (0, import_node_util2.parseArgs)({
6900
+ const parsed = (0, import_node_util.parseArgs)({
6862
6901
  args: argv,
6863
6902
  allowPositionals: true,
6864
6903
  options: {
@@ -6911,7 +6950,7 @@ async function runImportSandboxImageCli(argv = process.argv.slice(2)) {
6911
6950
  { emit: ndjsonStdoutEmit, _allowPat: true }
6912
6951
  );
6913
6952
  }
6914
- var import_node_path3, import_node_os2, import_node_fs2, import_node_util2, cachedNativeBinding, cachedNativeBindingError, DEFAULT_IMAGE_NAME2;
6953
+ var import_node_path3, import_node_os2, import_node_fs2, import_node_util, cachedNativeBinding, cachedNativeBindingError, DEFAULT_IMAGE_NAME2, __imageBuildInternals;
6915
6954
  var init_sandbox_image = __esm({
6916
6955
  "src/sandbox-image.ts"() {
6917
6956
  "use strict";
@@ -6919,11 +6958,21 @@ var init_sandbox_image = __esm({
6919
6958
  import_node_path3 = __toESM(require("path"), 1);
6920
6959
  import_node_os2 = __toESM(require("os"), 1);
6921
6960
  import_node_fs2 = require("fs");
6922
- import_node_util2 = require("util");
6923
- init_cloud_client();
6961
+ import_node_util = require("util");
6924
6962
  init_image();
6925
6963
  init_native_binding();
6964
+ init_image_builds();
6926
6965
  DEFAULT_IMAGE_NAME2 = "default";
6966
+ __imageBuildInternals = {
6967
+ loadNativeBinding: () => loadNativeBinding(),
6968
+ buildContextFromEnv: () => buildContextFromEnv(),
6969
+ stderrEmit: (event) => stderrEmit(event),
6970
+ noopEmit: (event) => noopEmit(event),
6971
+ eventToEmitDict: (event) => eventToEmitDict(event),
6972
+ imageRequiresContext: (image) => imageRequiresContext(image),
6973
+ defaultRegisteredName: (dockerfilePath) => defaultRegisteredName(dockerfilePath),
6974
+ defaultRegisteredNameFromImage: (reference) => defaultRegisteredNameFromImage(reference)
6975
+ };
6927
6976
  }
6928
6977
  });
6929
6978
 
@@ -6948,7 +6997,20 @@ __export(index_exports, {
6948
6997
  Headers: () => Headers,
6949
6998
  HttpBody: () => HttpBody,
6950
6999
  Image: () => Image,
7000
+ ImageBuildCancellationOutcome: () => ImageBuildCancellationOutcome,
7001
+ ImageBuildCancelledError: () => ImageBuildCancelledError,
7002
+ ImageBuildError: () => ImageBuildError,
7003
+ ImageBuildErrorCode: () => ImageBuildErrorCode,
7004
+ ImageBuildFailedError: () => ImageBuildFailedError,
7005
+ ImageBuildHandle: () => ImageBuildHandle,
7006
+ ImageBuildInProgressError: () => ImageBuildInProgressError,
7007
+ ImageBuildInterruptedError: () => ImageBuildInterruptedError,
7008
+ ImageBuildKind: () => ImageBuildKind,
7009
+ ImageBuildNotFoundError: () => ImageBuildNotFoundError,
6951
7010
  ImageBuildOperationType: () => ImageBuildOperationType,
7011
+ ImageBuildPhase: () => ImageBuildPhase,
7012
+ ImageBuildStatus: () => ImageBuildStatus,
7013
+ ImageBuildTimeoutError: () => ImageBuildTimeoutError,
6952
7014
  MountError: () => MountError,
6953
7015
  OutputMode: () => OutputMode,
6954
7016
  PendingSandbox: () => PendingSandbox,
@@ -6981,12 +7043,14 @@ __export(index_exports, {
6981
7043
  TERMINATION_REASON_CANCELLED: () => TERMINATION_REASON_CANCELLED,
6982
7044
  TERMINATION_REASON_NO_CAPACITY: () => TERMINATION_REASON_NO_CAPACITY,
6983
7045
  TcpTunnel: () => TcpTunnel,
7046
+ cancelImageBuild: () => cancelImageBuild,
6984
7047
  createFileSystem: () => createFileSystem,
6985
7048
  createSandboxImage: () => createSandboxImage,
6986
7049
  deleteFileSystem: () => deleteFileSystem,
6987
7050
  deleteSandboxImage: () => deleteSandboxImage,
6988
7051
  dockerfileContent: () => dockerfileContent,
6989
7052
  findSandboxImageByName: () => findSandboxImageByName,
7053
+ getImageBuild: () => getImageBuild,
6990
7054
  importSandboxImage: () => importSandboxImage,
6991
7055
  isSandboxPending: () => isSandboxPending,
6992
7056
  listFileSystems: () => listFileSystems,
@@ -6998,7 +7062,10 @@ __export(index_exports, {
6998
7062
  runLocal: () => runLocal,
6999
7063
  runRemote: () => runRemote,
7000
7064
  sandboxUrlFromIngressEndpoint: () => sandboxUrlFromIngressEndpoint,
7001
- schema: () => schema
7065
+ schema: () => schema,
7066
+ startImageBuild: () => startImageBuild,
7067
+ startImageImport: () => startImageImport,
7068
+ waitImageBuild: () => waitImageBuild
7002
7069
  });
7003
7070
  module.exports = __toCommonJS(index_exports);
7004
7071
  init_cjs_shims();
@@ -7008,11 +7075,546 @@ init_pending_sandbox();
7008
7075
  init_sandbox();
7009
7076
  init_desktop();
7010
7077
  init_tunnel();
7011
- init_cloud_client();
7078
+
7079
+ // src/cloud-client.ts
7080
+ init_cjs_shims();
7081
+ var import_nanoid = require("nanoid");
7082
+ init_defaults();
7083
+
7084
+ // src/native-cloud.ts
7085
+ init_cjs_shims();
7086
+ init_native_sandbox();
7087
+ init_native_worker_client();
7088
+ var NativeCloudTransport = class {
7089
+ constructor(options) {
7090
+ this.options = options;
7091
+ if (!Number.isSafeInteger(options.maxRetries) || options.maxRetries < 0 || options.maxRetries > 4294967295) {
7092
+ throw new RangeError("maxRetries must be a non-negative 32-bit integer");
7093
+ }
7094
+ if (!Number.isFinite(options.retryBackoffMs) || options.retryBackoffMs < 0) {
7095
+ throw new RangeError("retryBackoffMs must be a non-negative finite number");
7096
+ }
7097
+ }
7098
+ native;
7099
+ closed = false;
7100
+ client() {
7101
+ if (this.closed) throw new Error("Tensorlake native client is closed");
7102
+ if (this.native) return this.native;
7103
+ const ctor = loadNativeSandboxBinding().NativeCloudClient;
7104
+ if (!ctor) throw new Error("Native binding does not export NativeCloudClient; rebuild with 'npm run build:native'");
7105
+ return this.native = new ctor(JSON.stringify(this.options));
7106
+ }
7107
+ close() {
7108
+ this.closed = true;
7109
+ releaseNativeHandle(this.native ?? null);
7110
+ this.native = void 0;
7111
+ }
7112
+ async requestResponse(method, path4, options) {
7113
+ const request = await serializeRequest(method, path4, options);
7114
+ const raw = await callNative(() => this.client().request(request));
7115
+ const response = new Response(
7116
+ [204, 205, 304].includes(raw.status) ? null : Uint8Array.from(raw.data).buffer,
7117
+ { status: raw.status, headers: JSON.parse(raw.headersJson) }
7118
+ );
7119
+ return Object.assign(response, { traceId: raw.traceId });
7120
+ }
7121
+ async requestJson(method, path4) {
7122
+ const response = await this.requestResponse(method, path4);
7123
+ const text = await response.text();
7124
+ const value = text ? JSON.parse(text) : null;
7125
+ return Object.assign(value ?? {}, { traceId: response.traceId });
7126
+ }
7127
+ async *stream(method, path4, signal) {
7128
+ if (signal?.aborted) return;
7129
+ const request = await serializeRequest(method, path4, { headers: { Accept: "text/event-stream" } });
7130
+ yield* nativeEventStream((emit) => this.client().stream(request, emit), void 0, signal);
7131
+ }
7132
+ };
7133
+ async function serializeRequest(method, path4, options) {
7134
+ const headers = { ...options?.headers };
7135
+ let body = options?.body;
7136
+ if (options?.json !== void 0) {
7137
+ body = JSON.stringify(options.json);
7138
+ if (!Object.keys(headers).some((key) => key.toLowerCase() === "content-type")) {
7139
+ headers["Content-Type"] = "application/json";
7140
+ }
7141
+ }
7142
+ const request = {
7143
+ method,
7144
+ path: path4,
7145
+ headersJson: JSON.stringify(headers),
7146
+ statusOnlyCodes: [...options?.statusOnlyCodes ?? []]
7147
+ };
7148
+ if (body instanceof FormData) {
7149
+ request.parts = [];
7150
+ for (const [name, value] of body.entries()) {
7151
+ 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" });
7152
+ }
7153
+ } else if (body !== void 0) {
7154
+ if (body instanceof Blob) request.body = Buffer.from(await body.arrayBuffer());
7155
+ else if (typeof body === "string") request.body = Buffer.from(body);
7156
+ else if (body instanceof ArrayBuffer) request.body = Buffer.from(new Uint8Array(body));
7157
+ else request.body = Buffer.from(body);
7158
+ }
7159
+ return request;
7160
+ }
7161
+
7162
+ // src/cloud-client.ts
7163
+ init_models();
7164
+ init_sandbox_image();
7165
+ var CloudClient = class _CloudClient {
7166
+ transport;
7167
+ apiUrl;
7168
+ apiKey;
7169
+ organizationId;
7170
+ projectId;
7171
+ namespace;
7172
+ constructor(options) {
7173
+ this.apiUrl = options?.apiUrl ?? API_URL;
7174
+ this.apiKey = options?.apiKey ?? API_KEY;
7175
+ this.organizationId = options?.organizationId;
7176
+ this.projectId = options?.projectId;
7177
+ this.namespace = options?.namespace ?? NAMESPACE;
7178
+ this.transport = new NativeCloudTransport({
7179
+ baseUrl: options?.apiUrl ?? API_URL,
7180
+ apiKey: options?.apiKey ?? API_KEY,
7181
+ organizationId: this.organizationId,
7182
+ projectId: this.projectId,
7183
+ maxRetries: options?.maxRetries ?? MAX_RETRIES,
7184
+ retryBackoffMs: options?.retryBackoffMs ?? RETRY_BACKOFF_MS,
7185
+ timeoutMs: DEFAULT_HTTP_TIMEOUT_MS,
7186
+ userAgent: `tensorlake-typescript-sdk/${SDK_VERSION}`
7187
+ });
7188
+ }
7189
+ static forCloud(options) {
7190
+ return new _CloudClient(options);
7191
+ }
7192
+ close() {
7193
+ this.transport.close();
7194
+ }
7195
+ async upsertApplication(manifest, codeZip, upgradeRunningRequests = false) {
7196
+ const applicationManifest = { ...manifest };
7197
+ let publicEndpointId = publicEndpointIdFromManifest(applicationManifest);
7198
+ if (applicationAllowsUnauthenticatedRequests(applicationManifest) && publicEndpointId === void 0) {
7199
+ const applicationName = applicationManifest.name;
7200
+ if (typeof applicationName === "string" && applicationName.length > 0) {
7201
+ publicEndpointId = await this.existingApplicationPublicEndpointId(applicationName);
7202
+ }
7203
+ publicEndpointId ??= generatePublicEndpointId();
7204
+ }
7205
+ if (publicEndpointId !== void 0) {
7206
+ applicationManifest.public_endpoint_id = publicEndpointId;
7207
+ delete applicationManifest.publicEndpointId;
7208
+ }
7209
+ const form = new FormData();
7210
+ form.append(
7211
+ "code",
7212
+ new Blob([toBlobPart(codeZip)], { type: "application/zip" }),
7213
+ "code.zip"
7214
+ );
7215
+ form.append("code_content_type", "application/zip");
7216
+ form.append("application", JSON.stringify(applicationManifest));
7217
+ form.append(
7218
+ "upgrade_requests_to_latest_code",
7219
+ String(upgradeRunningRequests)
7220
+ );
7221
+ await this.transport.requestResponse("POST", this.namespacePath("applications"), {
7222
+ body: form
7223
+ });
7224
+ }
7225
+ async deleteApplication(applicationName) {
7226
+ await this.transport.requestResponse(
7227
+ "DELETE",
7228
+ this.namespacePath(`applications/${encodeURIComponent(applicationName)}`)
7229
+ );
7230
+ }
7231
+ /**
7232
+ * Delete a registered sandbox image by name or id through the merged
7233
+ * catalog, with this client's credentials: an `image_` id or a name the
7234
+ * Image Service knows deletes a CAS image, a `sandbox_template_` id or a
7235
+ * name registered only in the platform registry deletes a legacy image.
7236
+ * Rejects when neither catalog knows the reference. The same semantics
7237
+ * and accepted differences as the module-level `deleteSandboxImage`.
7238
+ */
7239
+ async deleteSandboxImage(imageName) {
7240
+ await deleteSandboxImageWithCredentials(this.catalogCredentials(), imageName);
7241
+ }
7242
+ /**
7243
+ * Look up a registered sandbox image by name or id through the merged
7244
+ * catalog, with this client's credentials. Returns the image in the
7245
+ * sandbox-template shape, or `null` when neither the Image Service nor the
7246
+ * platform registry knows the reference. An explicit organization/project
7247
+ * scope (the client's, or the call's override) addresses that project's
7248
+ * routes directly, as before; without one the key's own scope applies.
7249
+ */
7250
+ async findSandboxImageByName(imageName, options) {
7251
+ return findSandboxImageByNameWithCredentials(
7252
+ this.catalogCredentials(options),
7253
+ imageName
7254
+ );
7255
+ }
7256
+ /**
7257
+ * List every registered sandbox image of the project (CAS and legacy, in
7258
+ * the sandbox-template shape, newest first) through the merged catalog,
7259
+ * with this client's credentials. An explicit organization/project scope
7260
+ * (the client's, or the call's override) addresses that project's routes
7261
+ * directly, as before; without one the key's own scope applies.
7262
+ */
7263
+ async listSandboxImages(options) {
7264
+ return listSandboxImagesWithCredentials(this.catalogCredentials(options));
7265
+ }
7266
+ catalogCredentials(options) {
7267
+ return {
7268
+ apiUrl: this.apiUrl,
7269
+ apiKey: this.apiKey,
7270
+ organizationId: options?.organizationId ?? this.organizationId,
7271
+ projectId: options?.projectId ?? this.projectId
7272
+ };
7273
+ }
7274
+ async applications() {
7275
+ const raw = await this.transport.requestJson(
7276
+ "GET",
7277
+ this.namespacePath("applications")
7278
+ );
7279
+ return (raw.applications ?? []).map(
7280
+ (application) => fromSnakeKeys(application)
7281
+ );
7282
+ }
7283
+ async applicationManifest(applicationName) {
7284
+ const raw = await this.transport.requestJson(
7285
+ "GET",
7286
+ this.namespacePath(`applications/${encodeURIComponent(applicationName)}`)
7287
+ );
7288
+ return fromSnakeKeys(raw);
7289
+ }
7290
+ async runRequest(applicationName, inputs = []) {
7291
+ const path4 = this.namespacePath(
7292
+ `applications/${encodeURIComponent(applicationName)}`
7293
+ );
7294
+ const response = inputs.length === 0 ? await this.transport.requestResponse("POST", path4, {
7295
+ body: new Uint8Array(),
7296
+ headers: { Accept: "application/json" }
7297
+ }) : inputs.length === 1 && inputs[0].name === "0" ? await this.transport.requestResponse("POST", path4, {
7298
+ body: toRequestBody(inputs[0].data),
7299
+ headers: {
7300
+ Accept: "application/json",
7301
+ "Content-Type": inputs[0].contentType
7302
+ }
7303
+ }) : await this.runMultipartRequest(path4, inputs);
7304
+ const body = await parseJsonResponse(response);
7305
+ const requestId = body?.request_id;
7306
+ if (!requestId) {
7307
+ throw new Error("missing request_id in run request response body");
7308
+ }
7309
+ return requestId;
7310
+ }
7311
+ async waitOnRequestCompletion(applicationName, requestId) {
7312
+ const stream = this.transport.stream(
7313
+ "GET",
7314
+ this.namespacePath(
7315
+ `applications/${encodeURIComponent(applicationName)}/requests/${encodeURIComponent(requestId)}/progress`
7316
+ )
7317
+ );
7318
+ for await (const event of stream) {
7319
+ if (Object.prototype.hasOwnProperty.call(event, "RequestFinished")) {
7320
+ return;
7321
+ }
7322
+ }
7323
+ throw new Error("progress stream ended before request completion");
7324
+ }
7325
+ async requestMetadata(applicationName, requestId) {
7326
+ const raw = await this.transport.requestJson(
7327
+ "GET",
7328
+ this.namespacePath(
7329
+ `applications/${encodeURIComponent(applicationName)}/requests/${encodeURIComponent(requestId)}`
7330
+ )
7331
+ );
7332
+ return fromSnakeKeys(raw);
7333
+ }
7334
+ async requestOutput(applicationName, requestId) {
7335
+ const response = await this.transport.requestResponse(
7336
+ "GET",
7337
+ this.namespacePath(
7338
+ `applications/${encodeURIComponent(applicationName)}/requests/${encodeURIComponent(requestId)}/output`
7339
+ )
7340
+ );
7341
+ const serializedValue = new Uint8Array(await response.arrayBuffer());
7342
+ const contentType = response.headers.get("content-type") ?? "";
7343
+ return {
7344
+ serializedValue,
7345
+ contentType
7346
+ };
7347
+ }
7348
+ async listSecrets(options) {
7349
+ const base = this.secretCollectionPath(
7350
+ options?.organizationId,
7351
+ options?.projectId
7352
+ );
7353
+ const raw = await this.transport.requestJson("GET", base);
7354
+ const pageSize = Math.max(0, options?.pageSize ?? 100);
7355
+ return Object.assign(
7356
+ {
7357
+ items: raw.slice(0, pageSize).map(secretFromMetadata),
7358
+ pagination: { total: raw.length }
7359
+ },
7360
+ { traceId: raw.traceId }
7361
+ );
7362
+ }
7363
+ async getSecret(secretId, options) {
7364
+ const base = this.secretCollectionPath(
7365
+ options?.organizationId,
7366
+ options?.projectId
7367
+ );
7368
+ const raw = await this.transport.requestJson(
7369
+ "GET",
7370
+ `${base}/${encodeURIComponent(secretId)}`
7371
+ );
7372
+ return Object.assign(secretFromMetadata(raw), { traceId: raw.traceId });
7373
+ }
7374
+ async upsertSecrets(secrets, options) {
7375
+ const base = this.secretCollectionPath(
7376
+ options?.organizationId,
7377
+ options?.projectId
7378
+ );
7379
+ if (Array.isArray(secrets)) {
7380
+ const results = [];
7381
+ for (const secret of secrets) {
7382
+ results.push(await this.upsertSecret(base, secret));
7383
+ }
7384
+ return results;
7385
+ }
7386
+ return this.upsertSecret(base, secrets);
7387
+ }
7388
+ async deleteSecret(secretId, options) {
7389
+ const base = this.secretCollectionPath(
7390
+ options?.organizationId,
7391
+ options?.projectId
7392
+ );
7393
+ await this.transport.requestResponse(
7394
+ "DELETE",
7395
+ `${base}/${encodeURIComponent(secretId)}`
7396
+ );
7397
+ }
7398
+ async upsertSecret(base, secret) {
7399
+ let response = await this.transport.requestResponse("POST", base, {
7400
+ json: secret,
7401
+ headers: { "Idempotency-Key": (0, import_nanoid.nanoid)() },
7402
+ statusOnlyCodes: /* @__PURE__ */ new Set([409])
7403
+ });
7404
+ if (response.status === 409) {
7405
+ const prefix = base.slice(0, -"/secrets".length);
7406
+ const existing = await this.transport.requestJson(
7407
+ "GET",
7408
+ `${prefix}/secret-names/${encodeURIComponent(secret.name)}`
7409
+ );
7410
+ response = await this.transport.requestResponse(
7411
+ "POST",
7412
+ `${base}/${encodeURIComponent(existing.id)}/versions`,
7413
+ {
7414
+ json: { value: secret.value },
7415
+ headers: { "Idempotency-Key": (0, import_nanoid.nanoid)() }
7416
+ }
7417
+ );
7418
+ }
7419
+ const metadata = await parseJsonResponse(response);
7420
+ return Object.assign(secretFromMetadata(metadata), {
7421
+ traceId: response.traceId
7422
+ });
7423
+ }
7424
+ async startImageBuild(buildServicePath, request) {
7425
+ const form = new FormData();
7426
+ form.append("graph_name", request.applicationName);
7427
+ form.append("graph_version", request.applicationVersion);
7428
+ form.append("graph_function_name", request.functionName);
7429
+ form.append("image_name", request.imageName);
7430
+ form.append("image_id", request.imageId);
7431
+ form.append(
7432
+ "context",
7433
+ new Blob([toBlobPart(request.buildContext)]),
7434
+ "context.tar.gz"
7435
+ );
7436
+ const response = await this.transport.requestResponse(
7437
+ "PUT",
7438
+ `${trimTrailingSlashes2(buildServicePath)}/builds`,
7439
+ { body: form }
7440
+ );
7441
+ const raw = await parseJsonResponse(response);
7442
+ return fromSnakeKeys(raw);
7443
+ }
7444
+ async createApplicationBuild(buildServicePath, request, imageContexts) {
7445
+ const form = createApplicationBuildForm(request, imageContexts);
7446
+ const response = await this.transport.requestResponse(
7447
+ "POST",
7448
+ trimTrailingSlashes2(buildServicePath),
7449
+ { body: form }
7450
+ );
7451
+ const raw = await parseJsonResponse(response);
7452
+ return fromSnakeKeys(raw);
7453
+ }
7454
+ async applicationBuildInfo(buildServicePath, applicationBuildId) {
7455
+ const raw = await this.transport.requestJson(
7456
+ "GET",
7457
+ `${trimTrailingSlashes2(buildServicePath)}/${encodeURIComponent(applicationBuildId)}`
7458
+ );
7459
+ return fromSnakeKeys(raw);
7460
+ }
7461
+ async cancelApplicationBuild(buildServicePath, applicationBuildId) {
7462
+ const raw = await this.transport.requestJson(
7463
+ "POST",
7464
+ `${trimTrailingSlashes2(buildServicePath)}/${encodeURIComponent(applicationBuildId)}/cancel`
7465
+ );
7466
+ return fromSnakeKeys(raw);
7467
+ }
7468
+ async buildInfo(buildServicePath, buildId) {
7469
+ const raw = await this.transport.requestJson(
7470
+ "GET",
7471
+ `${trimTrailingSlashes2(buildServicePath)}/builds/${encodeURIComponent(buildId)}`
7472
+ );
7473
+ return fromSnakeKeys(raw);
7474
+ }
7475
+ async cancelBuild(buildServicePath, buildId) {
7476
+ await this.transport.requestResponse(
7477
+ "POST",
7478
+ `${trimTrailingSlashes2(buildServicePath)}/builds/${encodeURIComponent(buildId)}/cancel`
7479
+ );
7480
+ }
7481
+ async *streamBuildLogs(buildServicePath, buildId, signal) {
7482
+ const stream = this.transport.stream(
7483
+ "GET",
7484
+ `${trimTrailingSlashes2(buildServicePath)}/builds/${encodeURIComponent(buildId)}/logs`,
7485
+ signal
7486
+ );
7487
+ for await (const event of stream) {
7488
+ yield fromSnakeKeys(event);
7489
+ }
7490
+ }
7491
+ async runMultipartRequest(path4, inputs) {
7492
+ const form = new FormData();
7493
+ for (const input of inputs) {
7494
+ form.append(
7495
+ input.name,
7496
+ new Blob([toBlobPart(input.data)], { type: input.contentType }),
7497
+ input.name
7498
+ );
7499
+ }
7500
+ return this.transport.requestResponse("POST", path4, {
7501
+ body: form,
7502
+ headers: { Accept: "application/json" }
7503
+ });
7504
+ }
7505
+ namespacePath(subpath) {
7506
+ return `/v1/namespaces/${encodeURIComponent(this.namespace)}/${subpath.replace(/^\/+/, "")}`;
7507
+ }
7508
+ async existingApplicationPublicEndpointId(applicationName) {
7509
+ const response = await this.transport.requestResponse(
7510
+ "GET",
7511
+ this.namespacePath(`applications/${encodeURIComponent(applicationName)}`),
7512
+ { statusOnlyCodes: /* @__PURE__ */ new Set([404]) }
7513
+ );
7514
+ if (response.status === 404) {
7515
+ return void 0;
7516
+ }
7517
+ const application = await parseJsonResponse(response);
7518
+ return publicEndpointIdFromManifest(application);
7519
+ }
7520
+ secretCollectionPath(organizationId, projectId) {
7521
+ const resolvedOrganizationId = organizationId ?? this.organizationId;
7522
+ const resolvedProjectId = projectId ?? this.projectId;
7523
+ if (!resolvedOrganizationId && !resolvedProjectId) {
7524
+ return this.namespacePath("secrets");
7525
+ }
7526
+ if (!resolvedOrganizationId || !resolvedProjectId) {
7527
+ throw new Error("organizationId and projectId must be provided together");
7528
+ }
7529
+ return this.namespacePath("secrets");
7530
+ }
7531
+ };
7532
+ function secretFromMetadata(metadata) {
7533
+ return {
7534
+ id: metadata.id,
7535
+ name: metadata.name,
7536
+ createdAt: new Date(metadata.created_at_ms)
7537
+ };
7538
+ }
7539
+ var UNAUTHENTICATED_REQUESTS = "unauthenticated_requests";
7540
+ function applicationAllowsUnauthenticatedRequests(manifest) {
7541
+ return Array.isArray(manifest.allow) && manifest.allow.includes(UNAUTHENTICATED_REQUESTS);
7542
+ }
7543
+ function publicEndpointIdFromManifest(manifest) {
7544
+ for (const key of ["public_endpoint_id", "publicEndpointId"]) {
7545
+ const value = manifest[key];
7546
+ if (typeof value === "string" && value.length > 0) {
7547
+ return value;
7548
+ }
7549
+ }
7550
+ return void 0;
7551
+ }
7552
+ function generatePublicEndpointId() {
7553
+ return `endpoint_${(0, import_nanoid.nanoid)()}`;
7554
+ }
7555
+ function createApplicationBuildForm(request, imageContexts) {
7556
+ const contextsByPartName = /* @__PURE__ */ new Map();
7557
+ for (const context of imageContexts) {
7558
+ if (contextsByPartName.has(context.contextTarPartName)) {
7559
+ throw new Error(
7560
+ `duplicate image context part name '${context.contextTarPartName}'`
7561
+ );
7562
+ }
7563
+ contextsByPartName.set(context.contextTarPartName, context);
7564
+ }
7565
+ const form = new FormData();
7566
+ form.append(
7567
+ "app_version",
7568
+ new Blob([JSON.stringify(request)], { type: "application/json" }),
7569
+ "app_version"
7570
+ );
7571
+ for (const image of request.images) {
7572
+ const context = contextsByPartName.get(image.contextTarPartName);
7573
+ if (!context) {
7574
+ throw new Error(
7575
+ `missing image context for part '${image.contextTarPartName}'`
7576
+ );
7577
+ }
7578
+ form.append(
7579
+ image.contextTarPartName,
7580
+ new Blob([toBlobPart(context.contextTarGz)]),
7581
+ `${image.contextTarPartName}.tar.gz`
7582
+ );
7583
+ }
7584
+ for (const context of imageContexts) {
7585
+ if (!request.images.some((image) => image.contextTarPartName === context.contextTarPartName)) {
7586
+ throw new Error(
7587
+ `unexpected image context for part '${context.contextTarPartName}'`
7588
+ );
7589
+ }
7590
+ }
7591
+ return form;
7592
+ }
7593
+ function trimTrailingSlashes2(value) {
7594
+ return value.endsWith("/") ? value.slice(0, -1) : value;
7595
+ }
7596
+ function toBlobPart(data) {
7597
+ if (typeof data === "string" || data instanceof Blob) {
7598
+ return data;
7599
+ }
7600
+ if (data instanceof Uint8Array) {
7601
+ return Uint8Array.from(data).buffer;
7602
+ }
7603
+ return data;
7604
+ }
7605
+ function toRequestBody(data) {
7606
+ return toBlobPart(data);
7607
+ }
7608
+ async function parseJsonResponse(response) {
7609
+ const text = await response.text();
7610
+ if (!text) {
7611
+ return void 0;
7612
+ }
7613
+ return JSON.parse(text);
7614
+ }
7012
7615
 
7013
7616
  // src/api-client.ts
7014
7617
  init_cjs_shims();
7015
- init_cloud_client();
7016
7618
 
7017
7619
  // src/filesystem.ts
7018
7620
  init_cjs_shims();
@@ -7021,21 +7623,21 @@ var import_node_crypto2 = require("crypto");
7021
7623
  // src/mount-cli.ts
7022
7624
  init_cjs_shims();
7023
7625
  var import_node_child_process = require("child_process");
7024
- var import_node_fs = require("fs");
7025
- var import_node_os = require("os");
7026
- var import_node_path = require("path");
7027
- var import_node_util = require("util");
7626
+ var import_node_fs3 = require("fs");
7627
+ var import_node_os3 = require("os");
7628
+ var import_node_path4 = require("path");
7629
+ var import_node_util2 = require("util");
7028
7630
 
7029
7631
  // src/filesystem-models.ts
7030
7632
  init_cjs_shims();
7031
7633
  var GIT_MODE_DIR = 16384;
7032
7634
  var GIT_MODE_SYMLINK = 40960;
7033
- function trimSlashes(path3) {
7635
+ function trimSlashes(path4) {
7034
7636
  let start = 0;
7035
- let end = path3.length;
7036
- while (start < end && path3.charCodeAt(start) === 47) start += 1;
7037
- while (end > start && path3.charCodeAt(end - 1) === 47) end -= 1;
7038
- return path3.slice(start, end);
7637
+ let end = path4.length;
7638
+ while (start < end && path4.charCodeAt(start) === 47) start += 1;
7639
+ while (end > start && path4.charCodeAt(end - 1) === 47) end -= 1;
7640
+ return path4.slice(start, end);
7039
7641
  }
7040
7642
  function fileEntryFromWire(entry, dirPath) {
7041
7643
  const mode = entry.mode ?? 33188;
@@ -7053,9 +7655,9 @@ function fileEntryFromWire(entry, dirPath) {
7053
7655
  }
7054
7656
  function mountStatusFromRaw(raw, localPath) {
7055
7657
  const mounted = "mounted" in raw ? Boolean(raw.mounted) : "active" in raw ? Boolean(raw.active) : true;
7056
- const path3 = String(raw.path || raw.mount_path || localPath || "");
7658
+ const path4 = String(raw.path || raw.mount_path || localPath || "");
7057
7659
  const filesystem = raw.filesystem || raw.file_system || raw.repository || null;
7058
- return { path: path3, filesystem, mounted, raw };
7660
+ return { path: path4, filesystem, mounted, raw };
7059
7661
  }
7060
7662
  var FilesystemError = class extends Error {
7061
7663
  constructor(message) {
@@ -7074,11 +7676,11 @@ var FilesystemNotFoundError = class extends FilesystemError {
7074
7676
  var FileNotFoundInFilesystemError = class extends FilesystemError {
7075
7677
  filesystem;
7076
7678
  path;
7077
- constructor(filesystem, path3) {
7078
- super(`File not found in filesystem ${filesystem}: ${path3}`);
7679
+ constructor(filesystem, path4) {
7680
+ super(`File not found in filesystem ${filesystem}: ${path4}`);
7079
7681
  this.name = "FileNotFoundInFilesystemError";
7080
7682
  this.filesystem = filesystem;
7081
- this.path = path3;
7683
+ this.path = path4;
7082
7684
  }
7083
7685
  };
7084
7686
  var FilesystemAPIError = class extends FilesystemError {
@@ -7113,7 +7715,7 @@ var CliNotFoundError = class extends MountError {
7113
7715
  };
7114
7716
 
7115
7717
  // src/mount-cli.ts
7116
- var execFileAsync = (0, import_node_util.promisify)(import_node_child_process.execFile);
7718
+ var execFileAsync = (0, import_node_util2.promisify)(import_node_child_process.execFile);
7117
7719
  var MountCli = class {
7118
7720
  constructor(command, envOverrides) {
7119
7721
  this.command = command;
@@ -7124,9 +7726,9 @@ var MountCli = class {
7124
7726
  const candidates = [];
7125
7727
  if (process.env.TENSORLAKE_CLI) candidates.push(process.env.TENSORLAKE_CLI);
7126
7728
  candidates.push("tl");
7127
- const installed = (0, import_node_path.join)((0, import_node_os.homedir)(), ".tensorlake", "bin", "tl");
7729
+ const installed = (0, import_node_path4.join)((0, import_node_os3.homedir)(), ".tensorlake", "bin", "tl");
7128
7730
  try {
7129
- (0, import_node_fs.accessSync)(installed, import_node_fs.constants.F_OK);
7731
+ (0, import_node_fs3.accessSync)(installed, import_node_fs3.constants.F_OK);
7130
7732
  candidates.push(installed);
7131
7733
  } catch {
7132
7734
  }
@@ -7432,8 +8034,8 @@ var Filesystem = class {
7432
8034
  }
7433
8035
  // -- writes -------------------------------------------------------------------
7434
8036
  /** Write one file. Returns the snapshot (version) the write produced. */
7435
- async writeFile(path3, data, message) {
7436
- return await this.writeFiles(/* @__PURE__ */ new Map([[path3, data]]), message);
8037
+ async writeFile(path4, data, message) {
8038
+ return await this.writeFiles(/* @__PURE__ */ new Map([[path4, data]]), message);
7437
8039
  }
7438
8040
  /** Write several files (and/or delete paths) in one atomic snapshot. */
7439
8041
  async writeFiles(files, message, deletes = []) {
@@ -7441,8 +8043,8 @@ var Filesystem = class {
7441
8043
  if (entries.length === 0 && deletes.length === 0) {
7442
8044
  throw new FilesystemError("nothing to write: no files or deletions given");
7443
8045
  }
7444
- const writes = entries.map(([path3, data]) => ({
7445
- path: path3,
8046
+ const writes = entries.map(([path4, data]) => ({
8047
+ path: path4,
7446
8048
  content: toBuffer(data)
7447
8049
  }));
7448
8050
  const resolvedMessage = message || `write ${writes.length} file(s) via SDK`;
@@ -7458,9 +8060,9 @@ var Filesystem = class {
7458
8060
  * Stream one local file directly to object storage in bounded parts.
7459
8061
  * This is the memory-bounded API for multi-GiB files.
7460
8062
  */
7461
- async writeFileFromPath(path3, localPath, message) {
8063
+ async writeFileFromPath(path4, localPath, message) {
7462
8064
  return await this.writeFilesFromPaths(
7463
- /* @__PURE__ */ new Map([[path3, localPath]]),
8065
+ /* @__PURE__ */ new Map([[path4, localPath]]),
7464
8066
  message
7465
8067
  );
7466
8068
  }
@@ -7473,7 +8075,7 @@ var Filesystem = class {
7473
8075
  if (entries.length === 0) {
7474
8076
  throw new FilesystemError("nothing to write: no local files given");
7475
8077
  }
7476
- const writes = entries.map(([path3, localPath]) => ({ path: path3, localPath }));
8078
+ const writes = entries.map(([path4, localPath]) => ({ path: path4, localPath }));
7477
8079
  const resolvedMessage = message || `write ${writes.length} local file(s) via SDK`;
7478
8080
  const branch = await this.branch();
7479
8081
  const traced = await callNative2(
@@ -7550,11 +8152,11 @@ var Filesystem = class {
7550
8152
  };
7551
8153
  }
7552
8154
  /** Delete one file. Returns the durable version the deletion produced. */
7553
- async deleteFile(path3, message) {
8155
+ async deleteFile(path4, message) {
7554
8156
  return await this.writeFiles(
7555
8157
  /* @__PURE__ */ new Map(),
7556
- message || `delete ${path3} via SDK`,
7557
- [path3]
8158
+ message || `delete ${path4} via SDK`,
8159
+ [path4]
7558
8160
  );
7559
8161
  }
7560
8162
  /**
@@ -7605,15 +8207,15 @@ var Filesystem = class {
7605
8207
  * Read a file's bytes at `version` (the current `main` head or a retained
7606
8208
  * snapshot id; defaults to the filesystem's current head).
7607
8209
  */
7608
- async readFile(path3, version) {
7609
- return (await this.readFileWithMetadata(path3, { version })).data;
8210
+ async readFile(path4, version) {
8211
+ return (await this.readFileWithMetadata(path4, { version })).data;
7610
8212
  }
7611
8213
  /**
7612
8214
  * Read bytes and immutable metadata in one request. A range is executed by
7613
8215
  * Artifact Storage, so callers never download the unrequested remainder.
7614
8216
  */
7615
- async readFileWithMetadata(path3, options = {}) {
7616
- if (trimSlashes(path3) === "") {
8217
+ async readFileWithMetadata(path4, options = {}) {
8218
+ if (trimSlashes(path4) === "") {
7617
8219
  throw new FilesystemError("file path must not be empty");
7618
8220
  }
7619
8221
  const range = options.range;
@@ -7626,12 +8228,12 @@ var Filesystem = class {
7626
8228
  const traced = await callNative2(
7627
8229
  () => this.native.readFilesystemFile(
7628
8230
  this.name,
7629
- path3,
8231
+ path4,
7630
8232
  resolvedVersion,
7631
8233
  range?.offset,
7632
8234
  range?.length
7633
8235
  ),
7634
- new FileNotFoundInFilesystemError(this.name, path3)
8236
+ new FileNotFoundInFilesystemError(this.name, path4)
7635
8237
  );
7636
8238
  const fullSize = traced.fullSize;
7637
8239
  if (!traced.contentId || fullSize === void 0 || !Number.isSafeInteger(fullSize) || fullSize < 0 || traced.data.byteLength > fullSize) {
@@ -7646,9 +8248,9 @@ var Filesystem = class {
7646
8248
  };
7647
8249
  }
7648
8250
  /** Read a file as UTF-8 text at `version`. Throws on non-UTF-8 content. */
7649
- async readText(path3, version) {
8251
+ async readText(path4, version) {
7650
8252
  return new TextDecoder("utf-8", { fatal: true, ignoreBOM: true }).decode(
7651
- await this.readFile(path3, version)
8253
+ await this.readFile(path4, version)
7652
8254
  );
7653
8255
  }
7654
8256
  /** List one directory (non-recursive) at `version`. */
@@ -7711,11 +8313,11 @@ var FilesystemMount = class {
7711
8313
  path;
7712
8314
  readonly;
7713
8315
  /** @internal — obtain instances via `FilesystemClient.mount()`. */
7714
- constructor(client, cli, filesystem, path3, readonly) {
8316
+ constructor(client, cli, filesystem, path4, readonly) {
7715
8317
  this.client = client;
7716
8318
  this.cli = cli;
7717
8319
  this.filesystem = filesystem;
7718
- this.path = path3;
8320
+ this.path = path4;
7719
8321
  this.readonly = readonly;
7720
8322
  }
7721
8323
  /** Flush pending local changes into a durable snapshot. */
@@ -7733,6 +8335,7 @@ var FilesystemMount = class {
7733
8335
  };
7734
8336
 
7735
8337
  // src/api-client.ts
8338
+ init_sandbox_image();
7736
8339
  init_errors();
7737
8340
  var APIClient = class {
7738
8341
  cloudClient;
@@ -7760,7 +8363,7 @@ var APIClient = class {
7760
8363
  await this.cloudClient.deleteApplication(applicationName);
7761
8364
  }
7762
8365
  async deleteSandboxImage(imageName) {
7763
- await this.cloudClient.deleteSandboxImage(imageName);
8366
+ await deleteSandboxImageWithCredentials(this.filesystemOptions, imageName);
7764
8367
  }
7765
8368
  async createFileSystem(name, description, options) {
7766
8369
  const filesystem = await new FilesystemClient(this.filesystemOptions).create(
@@ -7830,7 +8433,7 @@ init_sandbox_image();
7830
8433
 
7831
8434
  // src/repository-mount.ts
7832
8435
  init_cjs_shims();
7833
- var import_node_path4 = require("path");
8436
+ var import_node_path5 = require("path");
7834
8437
  function requireNonEmpty(value, name) {
7835
8438
  if (typeof value !== "string" || value.length === 0) {
7836
8439
  throw new TypeError(`${name} must be a non-empty string`);
@@ -7847,28 +8450,28 @@ var GitCli = class extends MountCli {
7847
8450
  if (options.readOnly && (options.publish || options.workspace !== void 0) || options.publish && options.workspace !== void 0) {
7848
8451
  throw new TypeError("readOnly, publish, and workspace are mutually exclusive");
7849
8452
  }
7850
- const path3 = (0, import_node_path4.resolve)(localPath);
8453
+ const path4 = (0, import_node_path5.resolve)(localPath);
7851
8454
  const args = ["mount"];
7852
8455
  if (options.readOnly) args.push("--ro");
7853
8456
  if (options.publish) args.push("--publish");
7854
8457
  if (options.workspace !== void 0) args.push(`--workspace=${options.workspace}`);
7855
- args.push("--", target, path3);
8458
+ args.push("--", target, path4);
7856
8459
  await this.run(args);
7857
- return new RepositoryMount(this, target, path3, options.readOnly ?? false);
8460
+ return new RepositoryMount(this, target, path4, options.readOnly ?? false);
7858
8461
  }
7859
8462
  async unmount(localPath, options = {}) {
7860
8463
  requireNonEmpty(localPath, "localPath");
7861
8464
  const args = ["unmount"];
7862
8465
  if (options.deleteWorkspace) args.push("--delete");
7863
8466
  if (options.discard) args.push("--discard");
7864
- args.push("--", (0, import_node_path4.resolve)(localPath));
8467
+ args.push("--", (0, import_node_path5.resolve)(localPath));
7865
8468
  await this.run(args);
7866
8469
  }
7867
8470
  async status(localPath) {
7868
8471
  const args = ["status", "--json"];
7869
8472
  if (localPath !== void 0) {
7870
8473
  requireNonEmpty(localPath, "localPath");
7871
- args.push("--", (0, import_node_path4.resolve)(localPath));
8474
+ args.push("--", (0, import_node_path5.resolve)(localPath));
7872
8475
  }
7873
8476
  const output = await this.run(args, 6e4);
7874
8477
  let raw;
@@ -7883,7 +8486,7 @@ var GitCli = class extends MountCli {
7883
8486
  }
7884
8487
  const stringField = (key) => typeof raw[key] === "string" ? raw[key] : null;
7885
8488
  return {
7886
- path: stringField("mountpoint") ?? (localPath === void 0 ? "" : (0, import_node_path4.resolve)(localPath)),
8489
+ path: stringField("mountpoint") ?? (localPath === void 0 ? "" : (0, import_node_path5.resolve)(localPath)),
7887
8490
  repository: stringField("repository"),
7888
8491
  reference: stringField("reference"),
7889
8492
  workspaceId: stringField("workspace"),
@@ -7892,44 +8495,44 @@ var GitCli = class extends MountCli {
7892
8495
  raw
7893
8496
  };
7894
8497
  }
7895
- async snapshot(path3, message) {
8498
+ async snapshot(path4, message) {
7896
8499
  const args = ["snapshot"];
7897
8500
  if (message !== void 0) args.push(`--message=${message}`);
7898
- args.push("--", path3);
8501
+ args.push("--", path4);
7899
8502
  await this.run(args);
7900
8503
  }
7901
- async sync(path3, target) {
7902
- const args = ["sync", "--", path3];
8504
+ async sync(path4, target) {
8505
+ const args = ["sync", "--", path4];
7903
8506
  if (target !== void 0) {
7904
8507
  requireNonEmpty(target, "target");
7905
8508
  args.push(target);
7906
8509
  }
7907
8510
  await this.run(args);
7908
8511
  }
7909
- async rebase(path3, target, failOnConflict) {
8512
+ async rebase(path4, target, failOnConflict) {
7910
8513
  requireNonEmpty(target, "target");
7911
8514
  const args = ["rebase"];
7912
8515
  if (failOnConflict) args.push("--fail-on-conflict");
7913
- args.push("--", path3, target);
8516
+ args.push("--", path4, target);
7914
8517
  await this.run(args);
7915
8518
  }
7916
- async promote(path3, branch, merge) {
8519
+ async promote(path4, branch, merge) {
7917
8520
  requireNonEmpty(branch, "branch");
7918
8521
  const args = ["promote"];
7919
8522
  if (merge) args.push("--merge");
7920
- args.push("--", path3, branch);
8523
+ args.push("--", path4, branch);
7921
8524
  await this.run(args);
7922
8525
  }
7923
- async prefetch(path3) {
7924
- await this.run(["prefetch", "--", path3]);
8526
+ async prefetch(path4) {
8527
+ await this.run(["prefetch", "--", path4]);
7925
8528
  }
7926
8529
  };
7927
8530
  var RepositoryMount = class {
7928
8531
  /** @internal Obtain instances via RepositoryClient.mount(). */
7929
- constructor(cli, target, path3, readOnly) {
8532
+ constructor(cli, target, path4, readOnly) {
7930
8533
  this.cli = cli;
7931
8534
  this.target = target;
7932
- this.path = path3;
8535
+ this.path = path4;
7933
8536
  this.readOnly = readOnly;
7934
8537
  }
7935
8538
  /** Inspect workspace state, pending changes, and daemon diagnostics. */
@@ -8164,6 +8767,7 @@ function validateTimeoutMs2(timeoutMs) {
8164
8767
 
8165
8768
  // src/index.ts
8166
8769
  init_sandbox_image();
8770
+ init_image_builds();
8167
8771
 
8168
8772
  // src/file-system.ts
8169
8773
  init_cjs_shims();
@@ -9547,38 +10151,38 @@ init_cjs_shims();
9547
10151
  var import_node_crypto4 = require("crypto");
9548
10152
  var textEncoder = new TextEncoder();
9549
10153
  var textDecoder = new TextDecoder("utf-8", { fatal: true });
9550
- function assertJSONValue(value, path3, seen) {
10154
+ function assertJSONValue(value, path4, seen) {
9551
10155
  if (value === null || typeof value === "string" || typeof value === "boolean") return;
9552
10156
  if (typeof value === "number") {
9553
- if (!Number.isFinite(value)) throw new SerializationError(`${path3} contains a non-finite number`);
10157
+ if (!Number.isFinite(value)) throw new SerializationError(`${path4} contains a non-finite number`);
9554
10158
  return;
9555
10159
  }
9556
10160
  if (typeof value !== "object") {
9557
- throw new SerializationError(`${path3} contains unsupported ${typeof value}`);
10161
+ throw new SerializationError(`${path4} contains unsupported ${typeof value}`);
9558
10162
  }
9559
10163
  if (isFile(value)) {
9560
- throw new SerializationError(`${path3} contains a nested File; File is only supported as a direct value`);
10164
+ throw new SerializationError(`${path4} contains a nested File; File is only supported as a direct value`);
9561
10165
  }
9562
10166
  if (isHttpBody(value)) {
9563
10167
  throw new SerializationError(
9564
- `${path3} contains a nested HttpBody; HttpBody is only supported as a direct value`
10168
+ `${path4} contains a nested HttpBody; HttpBody is only supported as a direct value`
9565
10169
  );
9566
10170
  }
9567
- if (seen.has(value)) throw new SerializationError(`${path3} contains a cycle`);
10171
+ if (seen.has(value)) throw new SerializationError(`${path4} contains a cycle`);
9568
10172
  if (Object.getPrototypeOf(value) !== Object.prototype && !Array.isArray(value)) {
9569
- throw new SerializationError(`${path3} contains unsupported ${value.constructor?.name ?? "object"}`);
10173
+ throw new SerializationError(`${path4} contains unsupported ${value.constructor?.name ?? "object"}`);
9570
10174
  }
9571
10175
  seen.add(value);
9572
10176
  if (Array.isArray(value)) {
9573
10177
  for (let index = 0; index < value.length; index += 1) {
9574
10178
  if (!Object.prototype.hasOwnProperty.call(value, index)) {
9575
- throw new SerializationError(`${path3} contains a sparse array entry at index ${index}`);
10179
+ throw new SerializationError(`${path4} contains a sparse array entry at index ${index}`);
9576
10180
  }
9577
- assertJSONValue(value[index], `${path3}[${index}]`, seen);
10181
+ assertJSONValue(value[index], `${path4}[${index}]`, seen);
9578
10182
  }
9579
10183
  } else {
9580
10184
  for (const [key, item] of Object.entries(value)) {
9581
- assertJSONValue(item, `${path3}.${key}`, seen);
10185
+ assertJSONValue(item, `${path4}.${key}`, seen);
9582
10186
  }
9583
10187
  }
9584
10188
  seen.delete(value);
@@ -10028,7 +10632,20 @@ init_models();
10028
10632
  Headers,
10029
10633
  HttpBody,
10030
10634
  Image,
10635
+ ImageBuildCancellationOutcome,
10636
+ ImageBuildCancelledError,
10637
+ ImageBuildError,
10638
+ ImageBuildErrorCode,
10639
+ ImageBuildFailedError,
10640
+ ImageBuildHandle,
10641
+ ImageBuildInProgressError,
10642
+ ImageBuildInterruptedError,
10643
+ ImageBuildKind,
10644
+ ImageBuildNotFoundError,
10031
10645
  ImageBuildOperationType,
10646
+ ImageBuildPhase,
10647
+ ImageBuildStatus,
10648
+ ImageBuildTimeoutError,
10032
10649
  MountError,
10033
10650
  OutputMode,
10034
10651
  PendingSandbox,
@@ -10061,12 +10678,14 @@ init_models();
10061
10678
  TERMINATION_REASON_CANCELLED,
10062
10679
  TERMINATION_REASON_NO_CAPACITY,
10063
10680
  TcpTunnel,
10681
+ cancelImageBuild,
10064
10682
  createFileSystem,
10065
10683
  createSandboxImage,
10066
10684
  deleteFileSystem,
10067
10685
  deleteSandboxImage,
10068
10686
  dockerfileContent,
10069
10687
  findSandboxImageByName,
10688
+ getImageBuild,
10070
10689
  importSandboxImage,
10071
10690
  isSandboxPending,
10072
10691
  listFileSystems,
@@ -10078,6 +10697,9 @@ init_models();
10078
10697
  runLocal,
10079
10698
  runRemote,
10080
10699
  sandboxUrlFromIngressEndpoint,
10081
- schema
10700
+ schema,
10701
+ startImageBuild,
10702
+ startImageImport,
10703
+ waitImageBuild
10082
10704
  });
10083
10705
  //# sourceMappingURL=index.cjs.map