tensorlake 0.5.131 → 0.5.133

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 (50) hide show
  1. package/README.md +27 -0
  2. package/dist/applications/index.cjs +492 -708
  3. package/dist/applications/index.cjs.map +1 -1
  4. package/dist/applications/index.d.cts +3 -3
  5. package/dist/applications/index.d.ts +3 -3
  6. package/dist/applications/index.js +493 -713
  7. package/dist/applications/index.js.map +1 -1
  8. package/dist/function-agent/main.cjs +5 -2
  9. package/dist/function-agent/main.cjs.map +1 -1
  10. package/dist/function-agent/main.js +6 -3
  11. package/dist/function-agent/main.js.map +1 -1
  12. package/dist/function-executor/main.cjs +6 -3
  13. package/dist/function-executor/main.cjs.map +1 -1
  14. package/dist/function-executor/main.js +7 -4
  15. package/dist/function-executor/main.js.map +1 -1
  16. package/dist/index.cjs +121 -418
  17. package/dist/index.cjs.map +1 -1
  18. package/dist/index.d.cts +8 -22
  19. package/dist/index.d.ts +8 -22
  20. package/dist/index.js +122 -423
  21. package/dist/index.js.map +1 -1
  22. package/dist/native-worker.cjs +1 -0
  23. package/dist/native-worker.cjs.map +1 -1
  24. package/dist/native-worker.js +1 -0
  25. package/dist/native-worker.js.map +1 -1
  26. package/dist/{remote-DRCCuRth.d.cts → remote-D95Y6Czr.d.cts} +1 -1
  27. package/dist/{remote-0dzBqScB.d.ts → remote-omwTzbfj.d.ts} +1 -1
  28. package/dist/{sandbox-image-Bf5bcxtO.d.cts → sandbox-image-ChzWDeZy.d.cts} +2 -0
  29. package/dist/{sandbox-image-Bf5bcxtO.d.ts → sandbox-image-ChzWDeZy.d.ts} +2 -0
  30. package/dist/sandbox-image.cjs +476 -453
  31. package/dist/sandbox-image.cjs.map +1 -1
  32. package/dist/sandbox-image.d.cts +1 -1
  33. package/dist/sandbox-image.d.ts +1 -1
  34. package/dist/sandbox-image.js +475 -456
  35. package/dist/sandbox-image.js.map +1 -1
  36. package/package.json +8 -8
  37. package/runtime/function-executor/manifest.json +14 -14
  38. package/runtime/function-executor/package/dist/function-executor/main.js +7 -4
  39. package/runtime/function-executor/package/dist/function-executor/main.js.map +1 -1
  40. package/runtime/function-executor/package/dist/native-worker.cjs +1 -0
  41. package/runtime/function-executor/package/dist/native-worker.cjs.map +1 -1
  42. package/runtime/function-executor/package/npm-shrinkwrap.json +2 -12
  43. package/runtime/function-executor/package/package.json +1 -2
  44. package/runtime/typescript-function-runner/manifest.json +13 -13
  45. package/runtime/typescript-function-runner/package/dist/function-agent/main.js +6 -3
  46. package/runtime/typescript-function-runner/package/dist/function-agent/main.js.map +1 -1
  47. package/runtime/typescript-function-runner/package/dist/native-worker.cjs +1 -0
  48. package/runtime/typescript-function-runner/package/dist/native-worker.cjs.map +1 -1
  49. package/runtime/typescript-function-runner/package/npm-shrinkwrap.json +20 -29
  50. package/runtime/typescript-function-runner/package/package.json +7 -7
@@ -41,12 +41,12 @@ var init_esm_shims = __esm({
41
41
  });
42
42
 
43
43
  // src/defaults.ts
44
- var SDK_VERSION, API_URL, API_KEY, NAMESPACE, SANDBOX_PROXY_URL, DEFAULT_HTTP_TIMEOUT_MS, MAX_RETRIES, RETRY_BACKOFF_MS, RETRYABLE_STATUS_CODES;
44
+ var SDK_VERSION, API_URL, API_KEY, NAMESPACE, SANDBOX_PROXY_URL, DEFAULT_HTTP_TIMEOUT_MS, MAX_RETRIES, RETRY_BACKOFF_MS;
45
45
  var init_defaults = __esm({
46
46
  "src/defaults.ts"() {
47
47
  "use strict";
48
48
  init_esm_shims();
49
- SDK_VERSION = "0.5.131";
49
+ SDK_VERSION = "0.5.133";
50
50
  API_URL = process.env.TENSORLAKE_API_URL ?? "https://api.tensorlake.ai";
51
51
  API_KEY = process.env.TENSORLAKE_API_KEY ?? void 0;
52
52
  NAMESPACE = process.env.INDEXIFY_NAMESPACE ?? "default";
@@ -54,33 +54,10 @@ var init_defaults = __esm({
54
54
  DEFAULT_HTTP_TIMEOUT_MS = 3e5;
55
55
  MAX_RETRIES = 3;
56
56
  RETRY_BACKOFF_MS = 500;
57
- RETRYABLE_STATUS_CODES = /* @__PURE__ */ new Set([429, 502, 503, 504]);
58
57
  }
59
58
  });
60
59
 
61
60
  // src/errors.ts
62
- function describeError(err) {
63
- const parts = [];
64
- const seen = /* @__PURE__ */ new Set();
65
- let current = err;
66
- for (let depth = 0; depth < 6; depth++) {
67
- if (current == null || typeof current !== "object" || seen.has(current)) {
68
- break;
69
- }
70
- seen.add(current);
71
- const e = current;
72
- const message = typeof e.message === "string" ? e.message.trim() : "";
73
- const code = typeof e.code === "string" ? e.code : void 0;
74
- let segment = message;
75
- if (code && (!message || !message.includes(code))) {
76
- segment = segment ? `${segment} (${code})` : code;
77
- }
78
- if (segment && !parts.includes(segment)) parts.push(segment);
79
- current = e.cause;
80
- }
81
- if (parts.length > 0) return parts.join(": ");
82
- return err instanceof Error ? err.message : String(err);
83
- }
84
61
  function formatErrorDetails(errorDetails) {
85
62
  if (errorDetails == null) return void 0;
86
63
  if (typeof errorDetails === "string") {
@@ -218,364 +195,464 @@ var init_errors = __esm({
218
195
  }
219
196
  });
220
197
 
221
- // src/sdk-timings.ts
222
- function sdkTimingsEnabled() {
223
- const value = process.env[SDK_TIMINGS_ENV_VAR];
224
- return value === "1" || value === "true" || value === "yes";
225
- }
226
- function sdkTimingPayloadsEnabled() {
227
- const value = process.env[SDK_TIMING_PAYLOADS_ENV_VAR];
228
- return value === "1" || value === "true" || value === "yes";
229
- }
230
- function nowMs() {
231
- return performance.now();
232
- }
233
- function logSdkTiming(op, phase, startedAt, fields = {}) {
234
- if (!sdkTimingsEnabled()) return;
235
- logSdkTimingEvent(op, phase, {
236
- ...fields,
237
- duration_ms: Math.round((nowMs() - startedAt) * 100) / 100
238
- });
239
- }
240
- function logSdkTimingEvent(op, phase, fields = {}) {
241
- if (!sdkTimingsEnabled()) return;
242
- const parts = [
243
- "[tensorlake:sdk-timing]",
244
- `op=${op}`,
245
- `phase=${phase}`
246
- ];
247
- for (const [key, value] of Object.entries(fields)) {
248
- if (value == null) continue;
249
- parts.push(`${key}=${formatSdkTimingValue(value)}`);
198
+ // src/native-worker-protocol.ts
199
+ var cancelNativeCall, closeNativeHandle;
200
+ var init_native_worker_protocol = __esm({
201
+ "src/native-worker-protocol.ts"() {
202
+ "use strict";
203
+ init_esm_shims();
204
+ cancelNativeCall = /* @__PURE__ */ Symbol.for("tensorlake.native.cancel.v1");
205
+ closeNativeHandle = /* @__PURE__ */ Symbol.for("tensorlake.native.close.v1");
250
206
  }
251
- console.error(parts.join(" "));
207
+ });
208
+
209
+ // src/url.ts
210
+ function trimTrailingSlashes(url) {
211
+ return url.endsWith("/") ? url.slice(0, -1) : url;
252
212
  }
253
- function formatSdkTimingValue(value) {
254
- if (typeof value === "number" || typeof value === "boolean") {
255
- return String(value);
256
- }
257
- if (/^[A-Za-z0-9_./:@-]+$/.test(value)) {
258
- return value;
213
+ function resolveProxyTarget(proxyUrl, sandboxId) {
214
+ try {
215
+ const parsed = new URL(proxyUrl);
216
+ const host = parsed.hostname;
217
+ if (host === "localhost" || host === "127.0.0.1") {
218
+ return {
219
+ baseUrl: trimTrailingSlashes(proxyUrl),
220
+ hostHeader: `${sandboxId}.local`,
221
+ sandboxIdHeader: void 0
222
+ };
223
+ }
224
+ const port = parsed.port ? `:${parsed.port}` : "";
225
+ return {
226
+ baseUrl: `${parsed.protocol}//${host}${port}`,
227
+ hostHeader: void 0,
228
+ sandboxIdHeader: sandboxId
229
+ };
230
+ } catch {
231
+ return {
232
+ baseUrl: `${trimTrailingSlashes(proxyUrl)}/${sandboxId}`,
233
+ hostHeader: void 0,
234
+ sandboxIdHeader: void 0
235
+ };
259
236
  }
260
- return JSON.stringify(value);
261
237
  }
262
- var SDK_TIMINGS_ENV_VAR, SDK_TIMING_PAYLOADS_ENV_VAR;
263
- var init_sdk_timings = __esm({
264
- "src/sdk-timings.ts"() {
238
+ var init_url = __esm({
239
+ "src/url.ts"() {
265
240
  "use strict";
266
241
  init_esm_shims();
267
- SDK_TIMINGS_ENV_VAR = "TENSORLAKE_SDK_TIMINGS";
268
- SDK_TIMING_PAYLOADS_ENV_VAR = "TENSORLAKE_SDK_TIMING_PAYLOADS";
242
+ init_defaults();
269
243
  }
270
244
  });
271
245
 
272
- // src/http.ts
273
- import {
274
- Agent,
275
- fetch as undiciFetch,
276
- setGlobalDispatcher
277
- } from "undici";
278
- function withTraceId(value, traceId) {
279
- if (value == null) {
280
- return { traceId };
281
- }
282
- return Object.assign(value, { traceId });
283
- }
284
- function hasHeader(headers, name) {
285
- const lowered = name.toLowerCase();
286
- return Object.keys(headers).some((key) => key.toLowerCase() === lowered);
287
- }
288
- function normalizeRequestBody(body) {
289
- if (body == null) {
290
- return void 0;
291
- }
292
- if (body instanceof Uint8Array) {
293
- return Uint8Array.from(body).buffer;
294
- }
295
- return body;
246
+ // src/native-worker-client.ts
247
+ import { createRequire } from "module";
248
+ import { Worker } from "worker_threads";
249
+ function createWorkerBinding(runtime) {
250
+ return {
251
+ NativeCloudClient: class {
252
+ constructor(...args) {
253
+ return runtime.handle("NativeCloudClient", args);
254
+ }
255
+ },
256
+ NativeSandboxClient: class {
257
+ constructor(...args) {
258
+ return runtime.handle("NativeSandboxClient", args);
259
+ }
260
+ },
261
+ NativeSandboxProxyClient: class {
262
+ constructor(...args) {
263
+ return runtime.handle("NativeSandboxProxyClient", args);
264
+ }
265
+ },
266
+ NativeRepositoryClient: class {
267
+ constructor(...args) {
268
+ return runtime.handle("NativeRepositoryClient", args);
269
+ }
270
+ },
271
+ validateManagedName: (name) => runtime.call(void 0, "validateManagedName", [name])
272
+ };
273
+ }
274
+ function workerBinding() {
275
+ return createWorkerBinding(
276
+ runtimes[runtimeKey] ??= new NativeWorkerClient()
277
+ );
296
278
  }
297
- function stripPathPayload(path4) {
298
- const queryStart = path4.search(/[?#]/);
299
- return queryStart === -1 ? path4 : path4.slice(0, queryStart);
279
+ function releaseNativeHandle(handle) {
280
+ handle?.[closeNativeHandle]?.();
300
281
  }
301
- function throwMappedError(status, body, path4) {
302
- let message = body;
282
+ var NativeWorkerClient, runtimeKey, runtimes;
283
+ var init_native_worker_client = __esm({
284
+ "src/native-worker-client.ts"() {
285
+ "use strict";
286
+ init_esm_shims();
287
+ init_native_worker_protocol();
288
+ init_url();
289
+ NativeWorkerClient = class {
290
+ constructor(workerPath = () => createRequire(import.meta.url).resolve(
291
+ "tensorlake/internal/native-worker"
292
+ )) {
293
+ this.workerPath = workerPath;
294
+ }
295
+ worker;
296
+ nextId = 1;
297
+ registered = /* @__PURE__ */ new Set();
298
+ pending = /* @__PURE__ */ new Map();
299
+ finalizers = new FinalizationRegistry(
300
+ (id) => this.release(id)
301
+ );
302
+ handle(kind, args, parent) {
303
+ const handle = { id: this.nextId++, kind, args, parent };
304
+ this.finalizers.register(handle, handle.id);
305
+ let closed = false;
306
+ return new Proxy(
307
+ {},
308
+ {
309
+ get: (_target, method) => {
310
+ if (method === "then") return void 0;
311
+ if (method === closeNativeHandle)
312
+ return () => {
313
+ closed = true;
314
+ this.release(handle.id);
315
+ };
316
+ if (method === "connectProxy")
317
+ return (...proxyArgs) => {
318
+ if (closed) throw new Error("Tensorlake native client is closed");
319
+ return this.handle("NativeSandboxProxyClient", proxyArgs, handle);
320
+ };
321
+ if (method === "baseUrl")
322
+ return () => resolveProxyTarget(String(args[0]), String(args[1])).baseUrl;
323
+ if (typeof method !== "string") return void 0;
324
+ return (...callArgs) => {
325
+ if (closed)
326
+ return Promise.reject(
327
+ new Error("Tensorlake native client is closed")
328
+ );
329
+ const emit = typeof callArgs.at(-1) === "function" ? callArgs.pop() : void 0;
330
+ return this.call(handle, method, callArgs, emit);
331
+ };
332
+ }
333
+ }
334
+ );
335
+ }
336
+ call(handle, method, args, emit) {
337
+ const id = this.nextId++;
338
+ let worker;
339
+ const promise = new Promise((resolve, reject) => {
340
+ try {
341
+ worker = this.getWorker();
342
+ this.pending.set(id, { resolve, reject, emit, handle });
343
+ worker.ref();
344
+ if (handle) this.register(handle, worker);
345
+ this.send(worker, {
346
+ type: "call",
347
+ id,
348
+ handleId: handle?.id,
349
+ method,
350
+ args,
351
+ stream: !!emit
352
+ });
353
+ } catch (error) {
354
+ this.pending.delete(id);
355
+ this.unrefIfIdle();
356
+ reject(error);
357
+ }
358
+ });
359
+ promise[cancelNativeCall] = () => {
360
+ const pending = this.pending.get(id);
361
+ if (pending && worker) {
362
+ pending.emit = void 0;
363
+ this.send(worker, { type: "cancel", id });
364
+ }
365
+ };
366
+ return promise;
367
+ }
368
+ getWorker() {
369
+ if (this.worker) return this.worker;
370
+ const worker = new Worker(this.workerPath(), {
371
+ // The bundled worker needs no application loaders or telemetry preloads.
372
+ // NODE_OPTIONS is parsed independently of execArgv by Node.
373
+ execArgv: [],
374
+ env: { ...process.env, NODE_OPTIONS: "" },
375
+ name: "tensorlake-native"
376
+ });
377
+ this.worker = worker;
378
+ worker.on("message", (message) => {
379
+ const pending = this.pending.get(message.id);
380
+ if (!pending || this.worker !== worker) return;
381
+ if (message.type === "event") {
382
+ Promise.resolve().then(() => pending.emit?.(message.value)).then(
383
+ () => {
384
+ if (this.worker === worker)
385
+ this.send(worker, { type: "ack", id: message.id });
386
+ },
387
+ (error) => {
388
+ this.send(worker, { type: "cancel", id: message.id });
389
+ pending.reject(error);
390
+ }
391
+ );
392
+ return;
393
+ }
394
+ this.pending.delete(message.id);
395
+ if (message.type === "error") {
396
+ const error = new Error(message.error.message);
397
+ error.name = message.error.name;
398
+ error.stack = message.error.stack ?? error.stack;
399
+ pending.reject(error);
400
+ } else {
401
+ pending.resolve(message.value);
402
+ }
403
+ this.unrefIfIdle();
404
+ });
405
+ const fail = (error) => {
406
+ if (this.worker !== worker) return;
407
+ this.worker = void 0;
408
+ this.registered.clear();
409
+ for (const pending of this.pending.values()) pending.reject(error);
410
+ this.pending.clear();
411
+ void worker.terminate();
412
+ };
413
+ worker.on("error", fail);
414
+ worker.on("messageerror", fail);
415
+ worker.on(
416
+ "exit",
417
+ (code) => fail(
418
+ new Error(
419
+ `Tensorlake native worker exited (${code}); in-flight operations were not retried`
420
+ )
421
+ )
422
+ );
423
+ worker.unref();
424
+ return worker;
425
+ }
426
+ register(handle, worker) {
427
+ if (this.registered.has(handle.id)) return;
428
+ if (handle.parent) this.register(handle.parent, worker);
429
+ this.send(worker, {
430
+ type: "create",
431
+ handle: { id: handle.id, kind: handle.kind, args: handle.args },
432
+ parentId: handle.parent?.id
433
+ });
434
+ this.registered.add(handle.id);
435
+ }
436
+ release(handleId) {
437
+ if (this.worker && this.registered.delete(handleId))
438
+ this.send(this.worker, { type: "release", handleId });
439
+ }
440
+ send(worker, message) {
441
+ worker.postMessage(message);
442
+ }
443
+ unrefIfIdle() {
444
+ if (this.pending.size === 0) this.worker?.unref();
445
+ }
446
+ };
447
+ runtimeKey = /* @__PURE__ */ Symbol.for(
448
+ `tensorlake.native.worker.${false ? "source" : "0.5.133"}.v1`
449
+ );
450
+ runtimes = globalThis;
451
+ }
452
+ });
453
+
454
+ // src/native-sandbox.ts
455
+ function loadNativeSandboxBinding() {
456
+ return cachedBinding ??= workerBinding();
457
+ }
458
+ function parseNativeError(error) {
459
+ const message = error instanceof Error ? error.message : typeof error === "string" ? error : "";
460
+ if (!message) return null;
303
461
  try {
304
- const parsed = JSON.parse(body);
305
- if (parsed.message) message = parsed.message;
306
- else if (parsed.error) message = parsed.error;
462
+ const parsed = JSON.parse(message);
463
+ if (parsed && typeof parsed.category === "string") {
464
+ return {
465
+ category: parsed.category,
466
+ status: typeof parsed.status === "number" ? parsed.status : null,
467
+ message: typeof parsed.message === "string" ? parsed.message : message
468
+ };
469
+ }
307
470
  } catch {
308
471
  }
472
+ return null;
473
+ }
474
+ function translateNativeError(error, context) {
475
+ const payload = parseNativeError(error);
476
+ if (!payload) {
477
+ if (error instanceof Error) return error;
478
+ return new SandboxError(String(error));
479
+ }
480
+ const { category, status, message } = payload;
481
+ if (category === "connection") {
482
+ return new SandboxConnectionError(message, { cause: error });
483
+ }
309
484
  if (status === 404) {
310
- if (path4.includes("sandbox-pools") || path4.includes("pools")) {
311
- const match = path4.match(/sandbox-pools\/([^/]+)/);
312
- if (match) throw new PoolNotFoundError(match[1]);
485
+ if (context?.notFoundKind === "pool" && context.poolId) {
486
+ return new PoolNotFoundError(context.poolId);
313
487
  }
314
- if (path4.includes("sandboxes")) {
315
- const match = path4.match(/sandboxes\/([^/]+)/);
316
- if (match) throw new SandboxNotFoundError(match[1]);
488
+ if (context?.notFoundKind === "sandbox" && context.sandboxId) {
489
+ return new SandboxNotFoundError(context.sandboxId);
317
490
  }
318
- throw new RemoteAPIError(404, message);
491
+ return new RemoteAPIError(404, message);
319
492
  }
320
- if (status === 409) {
321
- if (path4.includes("sandbox-pools") || path4.includes("pools")) {
322
- const match = path4.match(/sandbox-pools\/([^/]+)/);
323
- if (match) throw new PoolInUseError(match[1], message);
324
- }
493
+ if (status === 409 && context?.poolId) {
494
+ return new PoolInUseError(context.poolId, message);
325
495
  }
326
- throw new RemoteAPIError(status, message);
496
+ if (typeof status === "number") {
497
+ return new RemoteAPIError(status, message);
498
+ }
499
+ return new SandboxError(message);
327
500
  }
328
- function anySignal(signals) {
329
- const controller = new AbortController();
330
- for (const signal of signals) {
331
- if (signal.aborted) {
332
- controller.abort(signal.reason);
333
- return controller.signal;
334
- }
335
- signal.addEventListener("abort", () => controller.abort(signal.reason), {
336
- once: true
501
+ async function callNative(fn, context) {
502
+ try {
503
+ return await fn();
504
+ } catch (error) {
505
+ throw translateNativeError(error, context);
506
+ }
507
+ }
508
+ async function* nativeEventStream(start, context, signal) {
509
+ if (signal?.aborted) return;
510
+ const queue = [];
511
+ let wake;
512
+ let finished = false;
513
+ let stopped = false;
514
+ let failure;
515
+ const notify = () => {
516
+ const resolve = wake;
517
+ wake = void 0;
518
+ resolve?.();
519
+ };
520
+ const emit = (value) => {
521
+ if (stopped) return Promise.resolve();
522
+ return new Promise((consumed) => {
523
+ queue.push({ value, consumed });
524
+ notify();
525
+ });
526
+ };
527
+ let call;
528
+ const onAbort = () => {
529
+ stopped = true;
530
+ call?.[cancelNativeCall]?.();
531
+ notify();
532
+ };
533
+ signal?.addEventListener("abort", onAbort, { once: true });
534
+ try {
535
+ call = start(emit);
536
+ void call.catch((error) => {
537
+ failure = error;
538
+ }).finally(() => {
539
+ finished = true;
540
+ notify();
337
541
  });
542
+ while (!stopped) {
543
+ const event = queue.shift();
544
+ if (event) {
545
+ try {
546
+ yield JSON.parse(event.value);
547
+ } finally {
548
+ event.consumed();
549
+ }
550
+ } else if (finished) {
551
+ break;
552
+ } else {
553
+ await new Promise((resolve) => {
554
+ wake = resolve;
555
+ });
556
+ }
557
+ }
558
+ if (!stopped && failure !== void 0) throw translateNativeError(failure, context);
559
+ } finally {
560
+ stopped = true;
561
+ signal?.removeEventListener("abort", onAbort);
562
+ call?.[cancelNativeCall]?.();
563
+ for (const event of queue) event.consumed();
338
564
  }
339
- return controller.signal;
340
- }
341
- function sleep(ms) {
342
- return new Promise((resolve) => setTimeout(resolve, ms));
343
565
  }
344
- var REQUEST_TIMEOUT_HEADER, HttpClient;
345
- var init_http = __esm({
346
- "src/http.ts"() {
566
+ var cachedBinding;
567
+ var init_native_sandbox = __esm({
568
+ "src/native-sandbox.ts"() {
347
569
  "use strict";
348
570
  init_esm_shims();
349
- init_defaults();
350
571
  init_errors();
351
- init_sdk_timings();
352
- REQUEST_TIMEOUT_HEADER = "X-Tensorlake-Request-Timeout-Ms";
353
- setGlobalDispatcher(
354
- new Agent({
355
- keepAliveTimeout: 6e4,
356
- allowH2: true
357
- })
358
- );
359
- HttpClient = class _HttpClient {
360
- baseUrl;
361
- headers;
362
- maxRetries;
363
- retryBackoffMs;
364
- timeoutMs;
365
- abortController = null;
572
+ init_native_worker_client();
573
+ init_native_worker_protocol();
574
+ }
575
+ });
576
+
577
+ // src/native-cloud.ts
578
+ async function serializeRequest(method, path4, options) {
579
+ const headers = { ...options?.headers };
580
+ let body = options?.body;
581
+ if (options?.json !== void 0) {
582
+ body = JSON.stringify(options.json);
583
+ if (!Object.keys(headers).some((key) => key.toLowerCase() === "content-type")) {
584
+ headers["Content-Type"] = "application/json";
585
+ }
586
+ }
587
+ const request = {
588
+ method,
589
+ path: path4,
590
+ headersJson: JSON.stringify(headers),
591
+ statusOnlyCodes: [...options?.statusOnlyCodes ?? []]
592
+ };
593
+ if (body instanceof FormData) {
594
+ request.parts = [];
595
+ for (const [name, value] of body.entries()) {
596
+ 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" });
597
+ }
598
+ } else if (body !== void 0) {
599
+ if (body instanceof Blob) request.body = Buffer.from(await body.arrayBuffer());
600
+ else if (typeof body === "string") request.body = Buffer.from(body);
601
+ else if (body instanceof ArrayBuffer) request.body = Buffer.from(new Uint8Array(body));
602
+ else request.body = Buffer.from(body);
603
+ }
604
+ return request;
605
+ }
606
+ var NativeCloudTransport;
607
+ var init_native_cloud = __esm({
608
+ "src/native-cloud.ts"() {
609
+ "use strict";
610
+ init_esm_shims();
611
+ init_native_sandbox();
612
+ init_native_worker_client();
613
+ NativeCloudTransport = class {
366
614
  constructor(options) {
367
- const url = options.baseUrl;
368
- this.baseUrl = url.endsWith("/") ? url.slice(0, -1) : url;
369
- this.maxRetries = options.maxRetries ?? MAX_RETRIES;
370
- this.retryBackoffMs = options.retryBackoffMs ?? RETRY_BACKOFF_MS;
371
- this.timeoutMs = options.timeoutMs === void 0 ? DEFAULT_HTTP_TIMEOUT_MS : options.timeoutMs;
372
- this.headers = {
373
- "User-Agent": `tensorlake-typescript-sdk/${SDK_VERSION}`
374
- };
375
- if (this.timeoutMs != null) {
376
- this.headers[REQUEST_TIMEOUT_HEADER] = String(this.timeoutMs);
377
- }
378
- if (options.apiKey) {
379
- this.headers["Authorization"] = `Bearer ${options.apiKey}`;
615
+ this.options = options;
616
+ if (!Number.isSafeInteger(options.maxRetries) || options.maxRetries < 0 || options.maxRetries > 4294967295) {
617
+ throw new RangeError("maxRetries must be a non-negative 32-bit integer");
380
618
  }
381
- if (options.organizationId) {
382
- this.headers["X-Forwarded-Organization-Id"] = options.organizationId;
619
+ if (!Number.isFinite(options.retryBackoffMs) || options.retryBackoffMs < 0) {
620
+ throw new RangeError("retryBackoffMs must be a non-negative finite number");
383
621
  }
384
- if (options.projectId) {
385
- this.headers["X-Forwarded-Project-Id"] = options.projectId;
386
- }
387
- if (options.hostHeader) {
388
- this.headers["Host"] = options.hostHeader;
389
- }
390
- if (options.sandboxIdHeader) {
391
- this.headers["X-Tensorlake-Sandbox-Id"] = options.sandboxIdHeader;
392
- }
393
- if (options.routingHint) {
394
- this.headers["X-Tensorlake-Route-Hint"] = options.routingHint;
395
- }
396
- }
397
- close() {
398
- this.abortController?.abort();
399
- this.abortController = null;
400
- }
401
- /** Make a JSON request, returning the parsed response body. */
402
- async requestJson(method, path4, options) {
403
- const response = await this.requestResponse(method, path4, {
404
- json: options?.body,
405
- headers: options?.headers,
406
- signal: options?.signal,
407
- retryableStatusCodes: options?.retryableStatusCodes,
408
- allowedErrorStatusCodes: options?.allowedErrorStatusCodes,
409
- allowHttpErrors: options?.allowHttpErrors
410
- });
411
- const text = await response.text();
412
- const data = text ? JSON.parse(text) : void 0;
413
- return withTraceId(data, response.traceId);
414
622
  }
415
- /** Make a request returning raw bytes. */
416
- async requestBytes(method, path4, options) {
417
- const headers = { ...options?.headers ?? {} };
418
- if (options?.contentType) {
419
- headers["Content-Type"] = options.contentType;
420
- }
421
- const response = await this.requestResponse(method, path4, {
422
- body: options?.body,
423
- headers,
424
- signal: options?.signal
425
- });
426
- const buffer = await response.arrayBuffer();
427
- return withTraceId(new Uint8Array(buffer), response.traceId);
623
+ native;
624
+ closed = false;
625
+ client() {
626
+ if (this.closed) throw new Error("Tensorlake native client is closed");
627
+ if (this.native) return this.native;
628
+ const ctor = loadNativeSandboxBinding().NativeCloudClient;
629
+ if (!ctor) throw new Error("Native binding does not export NativeCloudClient; rebuild with 'npm run build:native'");
630
+ return this.native = new ctor(JSON.stringify(this.options));
428
631
  }
429
- /** Make a request and return the response body as an SSE stream. */
430
- async requestStream(method, path4, options) {
431
- const response = await this.requestResponse(method, path4, {
432
- json: options?.json,
433
- headers: { Accept: "text/event-stream" },
434
- signal: options?.signal
435
- });
436
- if (!response.body) {
437
- throw new RemoteAPIError(
438
- response.status,
439
- "No response body for SSE stream"
440
- );
441
- }
442
- return withTraceId(response.body, response.traceId);
632
+ close() {
633
+ this.closed = true;
634
+ releaseNativeHandle(this.native ?? null);
635
+ this.native = void 0;
443
636
  }
444
- /** Make a request and return the raw Response. */
445
637
  async requestResponse(method, path4, options) {
446
- const headers = {
447
- ...this.headers,
448
- ...options?.headers ?? {}
449
- };
450
- const hasJsonBody = options?.json !== void 0;
451
- if (hasJsonBody && !hasHeader(headers, "Content-Type")) {
452
- headers["Content-Type"] = "application/json";
453
- }
454
- const body = hasJsonBody ? JSON.stringify(options?.json) : normalizeRequestBody(options?.body);
455
- const { response, traceId } = await this.doFetch(
456
- method,
457
- path4,
458
- body,
459
- headers,
460
- options?.signal,
461
- options?.allowHttpErrors ?? false,
462
- options?.retryableStatusCodes ?? RETRYABLE_STATUS_CODES,
463
- options?.allowedErrorStatusCodes ?? /* @__PURE__ */ new Set()
638
+ const request = await serializeRequest(method, path4, options);
639
+ const raw = await callNative(() => this.client().request(request));
640
+ const response = new Response(
641
+ [204, 205, 304].includes(raw.status) ? null : Uint8Array.from(raw.data).buffer,
642
+ { status: raw.status, headers: JSON.parse(raw.headersJson) }
464
643
  );
465
- return withTraceId(response, traceId);
644
+ return Object.assign(response, { traceId: raw.traceId });
466
645
  }
467
- static makeTraceparent() {
468
- const randomHex = (bytes) => Array.from(crypto.getRandomValues(new Uint8Array(bytes))).map((b) => b.toString(16).padStart(2, "0")).join("");
469
- const traceId = randomHex(16);
470
- const spanId = randomHex(8);
471
- return { traceparent: `00-${traceId}-${spanId}-01`, traceId };
646
+ async requestJson(method, path4) {
647
+ const response = await this.requestResponse(method, path4);
648
+ const text = await response.text();
649
+ const value = text ? JSON.parse(text) : null;
650
+ return Object.assign(value ?? {}, { traceId: response.traceId });
472
651
  }
473
- async doFetch(method, path4, body, headers, signal, allowHttpErrors = false, retryableStatusCodes = RETRYABLE_STATUS_CODES, allowedErrorStatusCodes = /* @__PURE__ */ new Set()) {
474
- const url = `${this.baseUrl}${path4}`;
475
- const { traceparent, traceId } = _HttpClient.makeTraceparent();
476
- headers["traceparent"] = traceparent;
477
- let lastError;
478
- const operationStart = nowMs();
479
- const timingPath = sdkTimingPayloadsEnabled() ? path4 : stripPathPayload(path4);
480
- for (let attempt = 0; attempt <= this.maxRetries; attempt++) {
481
- if (attempt > 0) {
482
- const delay = this.retryBackoffMs * Math.pow(2, attempt - 1);
483
- logSdkTimingEvent("http.request", "retry_sleep_start", {
484
- method,
485
- path: timingPath,
486
- attempt,
487
- delay_ms: delay,
488
- server_trace_id: traceId
489
- });
490
- await sleep(delay);
491
- }
492
- this.abortController = new AbortController();
493
- let timedOut = false;
494
- const timeoutId = this.timeoutMs == null ? null : setTimeout(() => {
495
- timedOut = true;
496
- this.abortController?.abort();
497
- }, this.timeoutMs);
498
- const combinedSignal = signal ? anySignal([signal, this.abortController.signal]) : this.abortController.signal;
499
- const attemptStart = nowMs();
500
- try {
501
- const response = await undiciFetch(url, {
502
- method,
503
- headers,
504
- body,
505
- signal: combinedSignal
506
- });
507
- if (timeoutId != null) clearTimeout(timeoutId);
508
- logSdkTiming("http.request", "headers", attemptStart, {
509
- method,
510
- path: timingPath,
511
- status: response.status,
512
- attempt,
513
- server_trace_id: traceId
514
- });
515
- if (response.ok) {
516
- logSdkTiming("http.request", "complete", operationStart, {
517
- method,
518
- path: timingPath,
519
- status: response.status,
520
- attempts: attempt + 1,
521
- server_trace_id: traceId
522
- });
523
- return { response, traceId };
524
- }
525
- if (retryableStatusCodes.has(response.status) && attempt < this.maxRetries) {
526
- lastError = new RemoteAPIError(
527
- response.status,
528
- await response.text().catch(() => "")
529
- );
530
- logSdkTimingEvent("http.request", "retryable_status", {
531
- method,
532
- path: timingPath,
533
- status: response.status,
534
- attempt,
535
- server_trace_id: traceId
536
- });
537
- continue;
538
- }
539
- if (allowHttpErrors || allowedErrorStatusCodes.has(response.status)) {
540
- logSdkTiming("http.request", "complete", operationStart, {
541
- method,
542
- path: timingPath,
543
- status: response.status,
544
- attempts: attempt + 1,
545
- server_trace_id: traceId
546
- });
547
- return { response, traceId };
548
- }
549
- const errorBody = await response.text().catch(() => "");
550
- throwMappedError(response.status, errorBody, path4);
551
- } catch (err) {
552
- if (timeoutId != null) clearTimeout(timeoutId);
553
- if (err instanceof RemoteAPIError || err instanceof SandboxNotFoundError || err instanceof PoolNotFoundError || err instanceof PoolInUseError) {
554
- throw err;
555
- }
556
- if (signal?.aborted && !timedOut) {
557
- throw new SandboxConnectionError("request aborted by caller", {
558
- cause: err
559
- });
560
- }
561
- lastError = err instanceof Error ? err : new Error(String(err));
562
- logSdkTiming("http.request", "error", attemptStart, {
563
- method,
564
- path: timingPath,
565
- attempt,
566
- server_trace_id: traceId,
567
- error: timedOut ? `request timed out after ${this.timeoutMs}ms` : describeError(err)
568
- });
569
- if (attempt >= this.maxRetries) {
570
- const detail = timedOut ? `request timed out after ${this.timeoutMs}ms` : describeError(err);
571
- throw new SandboxConnectionError(detail, { cause: err });
572
- }
573
- }
574
- }
575
- throw new SandboxConnectionError(
576
- lastError ? describeError(lastError) : "request failed",
577
- { cause: lastError }
578
- );
652
+ async *stream(method, path4, signal) {
653
+ if (signal?.aborted) return;
654
+ const request = await serializeRequest(method, path4, { headers: { Accept: "text/event-stream" } });
655
+ yield* nativeEventStream((emit) => this.client().stream(request, emit), void 0, signal);
579
656
  }
580
657
  };
581
658
  }
@@ -631,65 +708,6 @@ var init_models = __esm({
631
708
  }
632
709
  });
633
710
 
634
- // src/sse.ts
635
- async function* parseSSEMessages(stream, signal) {
636
- const reader = stream.getReader();
637
- const decoder = new TextDecoder();
638
- let buffer = "";
639
- try {
640
- while (true) {
641
- if (signal?.aborted) break;
642
- const { done, value } = await reader.read();
643
- if (done) break;
644
- buffer += decoder.decode(value, { stream: true });
645
- const parts = buffer.split(/\r?\n\r?\n/);
646
- buffer = parts.pop() ?? "";
647
- for (const part of parts) {
648
- const lines = part.split(/\r?\n/);
649
- const dataLines = [];
650
- let event;
651
- let id;
652
- for (const line of lines) {
653
- if (!line || line.startsWith(":")) continue;
654
- const separator = line.indexOf(":");
655
- const field = separator === -1 ? line : line.slice(0, separator);
656
- let value2 = separator === -1 ? "" : line.slice(separator + 1);
657
- if (value2.startsWith(" ")) {
658
- value2 = value2.slice(1);
659
- }
660
- if (field === "data") {
661
- dataLines.push(value2);
662
- } else if (field === "event") {
663
- event = value2;
664
- } else if (field === "id") {
665
- id = value2;
666
- }
667
- }
668
- if (dataLines.length > 0 || event || id) {
669
- yield { data: dataLines.join("\n"), event, id };
670
- }
671
- }
672
- }
673
- } finally {
674
- reader.releaseLock();
675
- }
676
- }
677
- async function* parseSSEStream(stream, signal) {
678
- for await (const message of parseSSEMessages(stream, signal)) {
679
- if (!message.data) continue;
680
- try {
681
- yield JSON.parse(message.data);
682
- } catch {
683
- }
684
- }
685
- }
686
- var init_sse = __esm({
687
- "src/sse.ts"() {
688
- "use strict";
689
- init_esm_shims();
690
- }
691
- });
692
-
693
711
  // src/cloud-client.ts
694
712
  import { nanoid } from "nanoid";
695
713
  function secretFromMetadata(metadata) {
@@ -752,7 +770,7 @@ function createApplicationBuildForm(request, imageContexts) {
752
770
  }
753
771
  return form;
754
772
  }
755
- function trimTrailingSlashes(value) {
773
+ function trimTrailingSlashes2(value) {
756
774
  return value.endsWith("/") ? value.slice(0, -1) : value;
757
775
  }
758
776
  function nextRequestPath(next) {
@@ -789,11 +807,10 @@ var init_cloud_client = __esm({
789
807
  "use strict";
790
808
  init_esm_shims();
791
809
  init_defaults();
792
- init_http();
810
+ init_native_cloud();
793
811
  init_models();
794
- init_sse();
795
812
  CloudClient = class _CloudClient {
796
- http;
813
+ transport;
797
814
  organizationId;
798
815
  projectId;
799
816
  namespace;
@@ -801,20 +818,22 @@ var init_cloud_client = __esm({
801
818
  this.organizationId = options?.organizationId;
802
819
  this.projectId = options?.projectId;
803
820
  this.namespace = options?.namespace ?? NAMESPACE;
804
- this.http = new HttpClient({
821
+ this.transport = new NativeCloudTransport({
805
822
  baseUrl: options?.apiUrl ?? API_URL,
806
823
  apiKey: options?.apiKey ?? API_KEY,
807
824
  organizationId: this.organizationId,
808
825
  projectId: this.projectId,
809
826
  maxRetries: options?.maxRetries ?? MAX_RETRIES,
810
- retryBackoffMs: options?.retryBackoffMs ?? RETRY_BACKOFF_MS
827
+ retryBackoffMs: options?.retryBackoffMs ?? RETRY_BACKOFF_MS,
828
+ timeoutMs: DEFAULT_HTTP_TIMEOUT_MS,
829
+ userAgent: `tensorlake-typescript-sdk/${SDK_VERSION}`
811
830
  });
812
831
  }
813
832
  static forCloud(options) {
814
833
  return new _CloudClient(options);
815
834
  }
816
835
  close() {
817
- this.http.close();
836
+ this.transport.close();
818
837
  }
819
838
  async upsertApplication(manifest, codeZip, upgradeRunningRequests = false) {
820
839
  const applicationManifest = { ...manifest };
@@ -842,18 +861,18 @@ var init_cloud_client = __esm({
842
861
  "upgrade_requests_to_latest_code",
843
862
  String(upgradeRunningRequests)
844
863
  );
845
- await this.http.requestResponse("POST", this.namespacePath("applications"), {
864
+ await this.transport.requestResponse("POST", this.namespacePath("applications"), {
846
865
  body: form
847
866
  });
848
867
  }
849
868
  async deleteApplication(applicationName) {
850
- await this.http.requestResponse(
869
+ await this.transport.requestResponse(
851
870
  "DELETE",
852
871
  this.namespacePath(`applications/${encodeURIComponent(applicationName)}`)
853
872
  );
854
873
  }
855
874
  async deleteSandboxImage(imageName) {
856
- await this.http.requestResponse(
875
+ await this.transport.requestResponse(
857
876
  "DELETE",
858
877
  this.namespacePath(`sandbox-images/${encodeURIComponent(imageName)}`)
859
878
  );
@@ -872,10 +891,10 @@ var init_cloud_client = __esm({
872
891
  options?.organizationId,
873
892
  options?.projectId
874
893
  );
875
- const response = await this.http.requestResponse(
894
+ const response = await this.transport.requestResponse(
876
895
  "GET",
877
896
  `${base}/by-name/${encodeURIComponent(imageName)}`,
878
- { allowedErrorStatusCodes: /* @__PURE__ */ new Set([404]) }
897
+ { statusOnlyCodes: /* @__PURE__ */ new Set([404]) }
879
898
  );
880
899
  if (response.status === 404) {
881
900
  return null;
@@ -897,7 +916,7 @@ var init_cloud_client = __esm({
897
916
  let path4 = `${base}?pageSize=100`;
898
917
  const templates = [];
899
918
  while (path4 !== null) {
900
- const page = await this.http.requestJson(
919
+ const page = await this.transport.requestJson(
901
920
  "GET",
902
921
  path4
903
922
  );
@@ -910,7 +929,7 @@ var init_cloud_client = __esm({
910
929
  return templates;
911
930
  }
912
931
  async applications() {
913
- const raw = await this.http.requestJson(
932
+ const raw = await this.transport.requestJson(
914
933
  "GET",
915
934
  this.namespacePath("applications")
916
935
  );
@@ -919,7 +938,7 @@ var init_cloud_client = __esm({
919
938
  );
920
939
  }
921
940
  async applicationManifest(applicationName) {
922
- const raw = await this.http.requestJson(
941
+ const raw = await this.transport.requestJson(
923
942
  "GET",
924
943
  this.namespacePath(`applications/${encodeURIComponent(applicationName)}`)
925
944
  );
@@ -929,10 +948,10 @@ var init_cloud_client = __esm({
929
948
  const path4 = this.namespacePath(
930
949
  `applications/${encodeURIComponent(applicationName)}`
931
950
  );
932
- const response = inputs.length === 0 ? await this.http.requestResponse("POST", path4, {
951
+ const response = inputs.length === 0 ? await this.transport.requestResponse("POST", path4, {
933
952
  body: new Uint8Array(),
934
953
  headers: { Accept: "application/json" }
935
- }) : inputs.length === 1 && inputs[0].name === "0" ? await this.http.requestResponse("POST", path4, {
954
+ }) : inputs.length === 1 && inputs[0].name === "0" ? await this.transport.requestResponse("POST", path4, {
936
955
  body: toRequestBody(inputs[0].data),
937
956
  headers: {
938
957
  Accept: "application/json",
@@ -947,13 +966,13 @@ var init_cloud_client = __esm({
947
966
  return requestId;
948
967
  }
949
968
  async waitOnRequestCompletion(applicationName, requestId) {
950
- const stream = await this.http.requestStream(
969
+ const stream = this.transport.stream(
951
970
  "GET",
952
971
  this.namespacePath(
953
972
  `applications/${encodeURIComponent(applicationName)}/requests/${encodeURIComponent(requestId)}/progress`
954
973
  )
955
974
  );
956
- for await (const event of parseSSEStream(stream)) {
975
+ for await (const event of stream) {
957
976
  if (Object.prototype.hasOwnProperty.call(event, "RequestFinished")) {
958
977
  return;
959
978
  }
@@ -961,7 +980,7 @@ var init_cloud_client = __esm({
961
980
  throw new Error("progress stream ended before request completion");
962
981
  }
963
982
  async requestMetadata(applicationName, requestId) {
964
- const raw = await this.http.requestJson(
983
+ const raw = await this.transport.requestJson(
965
984
  "GET",
966
985
  this.namespacePath(
967
986
  `applications/${encodeURIComponent(applicationName)}/requests/${encodeURIComponent(requestId)}`
@@ -970,7 +989,7 @@ var init_cloud_client = __esm({
970
989
  return fromSnakeKeys(raw);
971
990
  }
972
991
  async requestOutput(applicationName, requestId) {
973
- const response = await this.http.requestResponse(
992
+ const response = await this.transport.requestResponse(
974
993
  "GET",
975
994
  this.namespacePath(
976
995
  `applications/${encodeURIComponent(applicationName)}/requests/${encodeURIComponent(requestId)}/output`
@@ -988,7 +1007,7 @@ var init_cloud_client = __esm({
988
1007
  options?.organizationId,
989
1008
  options?.projectId
990
1009
  );
991
- const raw = await this.http.requestJson("GET", base);
1010
+ const raw = await this.transport.requestJson("GET", base);
992
1011
  const pageSize = Math.max(0, options?.pageSize ?? 100);
993
1012
  return Object.assign(
994
1013
  {
@@ -1003,7 +1022,7 @@ var init_cloud_client = __esm({
1003
1022
  options?.organizationId,
1004
1023
  options?.projectId
1005
1024
  );
1006
- const raw = await this.http.requestJson(
1025
+ const raw = await this.transport.requestJson(
1007
1026
  "GET",
1008
1027
  `${base}/${encodeURIComponent(secretId)}`
1009
1028
  );
@@ -1028,24 +1047,24 @@ var init_cloud_client = __esm({
1028
1047
  options?.organizationId,
1029
1048
  options?.projectId
1030
1049
  );
1031
- await this.http.requestResponse(
1050
+ await this.transport.requestResponse(
1032
1051
  "DELETE",
1033
1052
  `${base}/${encodeURIComponent(secretId)}`
1034
1053
  );
1035
1054
  }
1036
1055
  async upsertSecret(base, secret) {
1037
- let response = await this.http.requestResponse("POST", base, {
1056
+ let response = await this.transport.requestResponse("POST", base, {
1038
1057
  json: secret,
1039
1058
  headers: { "Idempotency-Key": nanoid() },
1040
- allowedErrorStatusCodes: /* @__PURE__ */ new Set([409])
1059
+ statusOnlyCodes: /* @__PURE__ */ new Set([409])
1041
1060
  });
1042
1061
  if (response.status === 409) {
1043
1062
  const prefix = base.slice(0, -"/secrets".length);
1044
- const existing = await this.http.requestJson(
1063
+ const existing = await this.transport.requestJson(
1045
1064
  "GET",
1046
1065
  `${prefix}/secret-names/${encodeURIComponent(secret.name)}`
1047
1066
  );
1048
- response = await this.http.requestResponse(
1067
+ response = await this.transport.requestResponse(
1049
1068
  "POST",
1050
1069
  `${base}/${encodeURIComponent(existing.id)}/versions`,
1051
1070
  {
@@ -1071,9 +1090,9 @@ var init_cloud_client = __esm({
1071
1090
  new Blob([toBlobPart(request.buildContext)]),
1072
1091
  "context.tar.gz"
1073
1092
  );
1074
- const response = await this.http.requestResponse(
1093
+ const response = await this.transport.requestResponse(
1075
1094
  "PUT",
1076
- `${trimTrailingSlashes(buildServicePath)}/builds`,
1095
+ `${trimTrailingSlashes2(buildServicePath)}/builds`,
1077
1096
  { body: form }
1078
1097
  );
1079
1098
  const raw = await parseJsonResponse(response);
@@ -1081,48 +1100,48 @@ var init_cloud_client = __esm({
1081
1100
  }
1082
1101
  async createApplicationBuild(buildServicePath, request, imageContexts) {
1083
1102
  const form = createApplicationBuildForm(request, imageContexts);
1084
- const response = await this.http.requestResponse(
1103
+ const response = await this.transport.requestResponse(
1085
1104
  "POST",
1086
- trimTrailingSlashes(buildServicePath),
1105
+ trimTrailingSlashes2(buildServicePath),
1087
1106
  { body: form }
1088
1107
  );
1089
1108
  const raw = await parseJsonResponse(response);
1090
1109
  return fromSnakeKeys(raw);
1091
1110
  }
1092
1111
  async applicationBuildInfo(buildServicePath, applicationBuildId) {
1093
- const raw = await this.http.requestJson(
1112
+ const raw = await this.transport.requestJson(
1094
1113
  "GET",
1095
- `${trimTrailingSlashes(buildServicePath)}/${encodeURIComponent(applicationBuildId)}`
1114
+ `${trimTrailingSlashes2(buildServicePath)}/${encodeURIComponent(applicationBuildId)}`
1096
1115
  );
1097
1116
  return fromSnakeKeys(raw);
1098
1117
  }
1099
1118
  async cancelApplicationBuild(buildServicePath, applicationBuildId) {
1100
- const raw = await this.http.requestJson(
1119
+ const raw = await this.transport.requestJson(
1101
1120
  "POST",
1102
- `${trimTrailingSlashes(buildServicePath)}/${encodeURIComponent(applicationBuildId)}/cancel`
1121
+ `${trimTrailingSlashes2(buildServicePath)}/${encodeURIComponent(applicationBuildId)}/cancel`
1103
1122
  );
1104
1123
  return fromSnakeKeys(raw);
1105
1124
  }
1106
1125
  async buildInfo(buildServicePath, buildId) {
1107
- const raw = await this.http.requestJson(
1126
+ const raw = await this.transport.requestJson(
1108
1127
  "GET",
1109
- `${trimTrailingSlashes(buildServicePath)}/builds/${encodeURIComponent(buildId)}`
1128
+ `${trimTrailingSlashes2(buildServicePath)}/builds/${encodeURIComponent(buildId)}`
1110
1129
  );
1111
1130
  return fromSnakeKeys(raw);
1112
1131
  }
1113
1132
  async cancelBuild(buildServicePath, buildId) {
1114
- await this.http.requestResponse(
1133
+ await this.transport.requestResponse(
1115
1134
  "POST",
1116
- `${trimTrailingSlashes(buildServicePath)}/builds/${encodeURIComponent(buildId)}/cancel`
1135
+ `${trimTrailingSlashes2(buildServicePath)}/builds/${encodeURIComponent(buildId)}/cancel`
1117
1136
  );
1118
1137
  }
1119
1138
  async *streamBuildLogs(buildServicePath, buildId, signal) {
1120
- const stream = await this.http.requestStream(
1139
+ const stream = this.transport.stream(
1121
1140
  "GET",
1122
- `${trimTrailingSlashes(buildServicePath)}/builds/${encodeURIComponent(buildId)}/logs`,
1123
- { signal }
1141
+ `${trimTrailingSlashes2(buildServicePath)}/builds/${encodeURIComponent(buildId)}/logs`,
1142
+ signal
1124
1143
  );
1125
- for await (const event of parseSSEStream(stream, signal)) {
1144
+ for await (const event of stream) {
1126
1145
  yield fromSnakeKeys(event);
1127
1146
  }
1128
1147
  }
@@ -1135,7 +1154,7 @@ var init_cloud_client = __esm({
1135
1154
  input.name
1136
1155
  );
1137
1156
  }
1138
- return this.http.requestResponse("POST", path4, {
1157
+ return this.transport.requestResponse("POST", path4, {
1139
1158
  body: form,
1140
1159
  headers: { Accept: "application/json" }
1141
1160
  });
@@ -1144,10 +1163,10 @@ var init_cloud_client = __esm({
1144
1163
  return `/v1/namespaces/${encodeURIComponent(this.namespace)}/${subpath.replace(/^\/+/, "")}`;
1145
1164
  }
1146
1165
  async existingApplicationPublicEndpointId(applicationName) {
1147
- const response = await this.http.requestResponse(
1166
+ const response = await this.transport.requestResponse(
1148
1167
  "GET",
1149
1168
  this.namespacePath(`applications/${encodeURIComponent(applicationName)}`),
1150
- { allowedErrorStatusCodes: /* @__PURE__ */ new Set([404]) }
1169
+ { statusOnlyCodes: /* @__PURE__ */ new Set([404]) }
1151
1170
  );
1152
1171
  if (response.status === 404) {
1153
1172
  return void 0;
@@ -1250,7 +1269,7 @@ var require_libc = __commonJS({
1250
1269
 
1251
1270
  // src/native-binding.ts
1252
1271
  import * as fs from "fs";
1253
- import { createRequire } from "module";
1272
+ import { createRequire as createRequire2 } from "module";
1254
1273
  import path2 from "path";
1255
1274
  import { fileURLToPath as fileURLToPath2 } from "url";
1256
1275
  function packageRoot() {
@@ -1294,7 +1313,7 @@ function nativePackageName(platform = process.platform, arch = process.arch, opt
1294
1313
  function loadNative() {
1295
1314
  const target = nativeTargetId();
1296
1315
  const bindingPath = nativeBindingPath();
1297
- const require2 = createRequire(import.meta.url);
1316
+ const require2 = createRequire2(import.meta.url);
1298
1317
  if (fs.existsSync(bindingPath)) return require2(bindingPath);
1299
1318
  const packageName = nativePackageName();
1300
1319
  if (!packageName) {
@@ -3833,249 +3852,10 @@ var MountCli = class {
3833
3852
 
3834
3853
  // src/filesystem.ts
3835
3854
  init_defaults();
3836
-
3837
- // src/native-sandbox.ts
3838
- init_esm_shims();
3839
- init_errors();
3840
-
3841
- // src/native-worker-client.ts
3842
- init_esm_shims();
3843
- import { createRequire as createRequire2 } from "module";
3844
- import { SHARE_ENV, Worker } from "worker_threads";
3845
-
3846
- // src/native-worker-protocol.ts
3847
- init_esm_shims();
3848
- var cancelNativeCall = /* @__PURE__ */ Symbol.for("tensorlake.native.cancel.v1");
3849
- var closeNativeHandle = /* @__PURE__ */ Symbol.for("tensorlake.native.close.v1");
3850
-
3851
- // src/url.ts
3852
- init_esm_shims();
3853
- init_defaults();
3854
- function trimTrailingSlashes2(url) {
3855
- return url.endsWith("/") ? url.slice(0, -1) : url;
3856
- }
3857
- function resolveProxyTarget(proxyUrl, sandboxId) {
3858
- try {
3859
- const parsed = new URL(proxyUrl);
3860
- const host = parsed.hostname;
3861
- if (host === "localhost" || host === "127.0.0.1") {
3862
- return {
3863
- baseUrl: trimTrailingSlashes2(proxyUrl),
3864
- hostHeader: `${sandboxId}.local`,
3865
- sandboxIdHeader: void 0
3866
- };
3867
- }
3868
- const port = parsed.port ? `:${parsed.port}` : "";
3869
- return {
3870
- baseUrl: `${parsed.protocol}//${host}${port}`,
3871
- hostHeader: void 0,
3872
- sandboxIdHeader: sandboxId
3873
- };
3874
- } catch {
3875
- return {
3876
- baseUrl: `${trimTrailingSlashes2(proxyUrl)}/${sandboxId}`,
3877
- hostHeader: void 0,
3878
- sandboxIdHeader: void 0
3879
- };
3880
- }
3881
- }
3882
-
3883
- // src/native-worker-client.ts
3884
- var NativeWorkerClient = class {
3885
- constructor(workerPath = () => createRequire2(import.meta.url).resolve(
3886
- "tensorlake/internal/native-worker"
3887
- )) {
3888
- this.workerPath = workerPath;
3889
- }
3890
- worker;
3891
- nextId = 1;
3892
- registered = /* @__PURE__ */ new Set();
3893
- pending = /* @__PURE__ */ new Map();
3894
- finalizers = new FinalizationRegistry(
3895
- (id) => this.release(id)
3896
- );
3897
- handle(kind, args, parent) {
3898
- const handle = { id: this.nextId++, kind, args, parent };
3899
- this.finalizers.register(handle, handle.id);
3900
- let closed = false;
3901
- return new Proxy(
3902
- {},
3903
- {
3904
- get: (_target, method) => {
3905
- if (method === "then") return void 0;
3906
- if (method === closeNativeHandle)
3907
- return () => {
3908
- closed = true;
3909
- this.release(handle.id);
3910
- };
3911
- if (method === "connectProxy")
3912
- return (...proxyArgs) => {
3913
- if (closed) throw new Error("Tensorlake native client is closed");
3914
- return this.handle("NativeSandboxProxyClient", proxyArgs, handle);
3915
- };
3916
- if (method === "baseUrl")
3917
- return () => resolveProxyTarget(String(args[0]), String(args[1])).baseUrl;
3918
- if (typeof method !== "string") return void 0;
3919
- return (...callArgs) => {
3920
- if (closed)
3921
- return Promise.reject(
3922
- new Error("Tensorlake native client is closed")
3923
- );
3924
- const emit = typeof callArgs.at(-1) === "function" ? callArgs.pop() : void 0;
3925
- return this.call(handle, method, callArgs, emit);
3926
- };
3927
- }
3928
- }
3929
- );
3930
- }
3931
- call(handle, method, args, emit) {
3932
- const id = this.nextId++;
3933
- let worker;
3934
- const promise = new Promise((resolve, reject) => {
3935
- try {
3936
- worker = this.getWorker();
3937
- this.pending.set(id, { resolve, reject, emit, handle });
3938
- worker.ref();
3939
- if (handle) this.register(handle, worker);
3940
- this.send(worker, {
3941
- type: "call",
3942
- id,
3943
- handleId: handle?.id,
3944
- method,
3945
- args,
3946
- stream: !!emit
3947
- });
3948
- } catch (error) {
3949
- this.pending.delete(id);
3950
- this.unrefIfIdle();
3951
- reject(error);
3952
- }
3953
- });
3954
- promise[cancelNativeCall] = () => {
3955
- const pending = this.pending.get(id);
3956
- if (pending && worker) {
3957
- pending.emit = void 0;
3958
- this.send(worker, { type: "cancel", id });
3959
- }
3960
- };
3961
- return promise;
3962
- }
3963
- getWorker() {
3964
- if (this.worker) return this.worker;
3965
- const worker = new Worker(this.workerPath(), {
3966
- env: SHARE_ENV,
3967
- name: "tensorlake-native"
3968
- });
3969
- this.worker = worker;
3970
- worker.on("message", (message) => {
3971
- const pending = this.pending.get(message.id);
3972
- if (!pending || this.worker !== worker) return;
3973
- if (message.type === "event") {
3974
- Promise.resolve().then(() => pending.emit?.(message.value)).then(
3975
- () => {
3976
- if (this.worker === worker)
3977
- this.send(worker, { type: "ack", id: message.id });
3978
- },
3979
- (error) => {
3980
- this.send(worker, { type: "cancel", id: message.id });
3981
- pending.reject(error);
3982
- }
3983
- );
3984
- return;
3985
- }
3986
- this.pending.delete(message.id);
3987
- if (message.type === "error") {
3988
- const error = new Error(message.error.message);
3989
- error.name = message.error.name;
3990
- error.stack = message.error.stack ?? error.stack;
3991
- pending.reject(error);
3992
- } else {
3993
- pending.resolve(message.value);
3994
- }
3995
- this.unrefIfIdle();
3996
- });
3997
- const fail = (error) => {
3998
- if (this.worker !== worker) return;
3999
- this.worker = void 0;
4000
- this.registered.clear();
4001
- for (const pending of this.pending.values()) pending.reject(error);
4002
- this.pending.clear();
4003
- void worker.terminate();
4004
- };
4005
- worker.on("error", fail);
4006
- worker.on("messageerror", fail);
4007
- worker.on(
4008
- "exit",
4009
- (code) => fail(
4010
- new Error(
4011
- `Tensorlake native worker exited (${code}); in-flight operations were not retried`
4012
- )
4013
- )
4014
- );
4015
- worker.unref();
4016
- return worker;
4017
- }
4018
- register(handle, worker) {
4019
- if (this.registered.has(handle.id)) return;
4020
- if (handle.parent) this.register(handle.parent, worker);
4021
- this.send(worker, {
4022
- type: "create",
4023
- handle: { id: handle.id, kind: handle.kind, args: handle.args },
4024
- parentId: handle.parent?.id
4025
- });
4026
- this.registered.add(handle.id);
4027
- }
4028
- release(handleId) {
4029
- if (this.worker && this.registered.delete(handleId))
4030
- this.send(this.worker, { type: "release", handleId });
4031
- }
4032
- send(worker, message) {
4033
- worker.postMessage(message);
4034
- }
4035
- unrefIfIdle() {
4036
- if (this.pending.size === 0) this.worker?.unref();
4037
- }
4038
- };
4039
- function createWorkerBinding(runtime) {
4040
- return {
4041
- NativeSandboxClient: class {
4042
- constructor(...args) {
4043
- return runtime.handle("NativeSandboxClient", args);
4044
- }
4045
- },
4046
- NativeSandboxProxyClient: class {
4047
- constructor(...args) {
4048
- return runtime.handle("NativeSandboxProxyClient", args);
4049
- }
4050
- },
4051
- NativeRepositoryClient: class {
4052
- constructor(...args) {
4053
- return runtime.handle("NativeRepositoryClient", args);
4054
- }
4055
- },
4056
- validateManagedName: (name) => runtime.call(void 0, "validateManagedName", [name])
4057
- };
4058
- }
4059
- var runtimeKey = /* @__PURE__ */ Symbol.for(
4060
- `tensorlake.native.worker.${false ? "source" : "0.5.131"}.v1`
4061
- );
4062
- var runtimes = globalThis;
4063
- function workerBinding() {
4064
- return createWorkerBinding(
4065
- runtimes[runtimeKey] ??= new NativeWorkerClient()
4066
- );
4067
- }
4068
-
4069
- // src/native-sandbox.ts
4070
- var cachedBinding;
4071
- function loadNativeSandboxBinding() {
4072
- return cachedBinding ??= workerBinding();
4073
- }
4074
-
4075
- // src/filesystem.ts
3855
+ init_native_sandbox();
4076
3856
  init_sandbox_image();
4077
3857
  var FILESYSTEM_REPO_KIND = "filesystem";
4078
- function translateNativeError(error, notFound) {
3858
+ function translateNativeError2(error, notFound) {
4079
3859
  const message = error instanceof Error ? error.message : String(error);
4080
3860
  let payload;
4081
3861
  try {
@@ -4098,11 +3878,11 @@ function translateNativeError(error, notFound) {
4098
3878
  }
4099
3879
  return new FilesystemError(detail);
4100
3880
  }
4101
- async function callNative(fn, notFound) {
3881
+ async function callNative2(fn, notFound) {
4102
3882
  try {
4103
3883
  return await fn();
4104
3884
  } catch (error) {
4105
- throw translateNativeError(error, notFound);
3885
+ throw translateNativeError2(error, notFound);
4106
3886
  }
4107
3887
  }
4108
3888
  var FsCli = class extends MountCli {
@@ -4204,7 +3984,7 @@ var FilesystemClient = class {
4204
3984
  if (name.length === 0) {
4205
3985
  throw new FilesystemError("filesystem name must not be empty");
4206
3986
  }
4207
- const raw = await callNative(() => this.native.createFilesystem(name));
3987
+ const raw = await callNative2(() => this.native.createFilesystem(name));
4208
3988
  const created = JSON.parse(raw);
4209
3989
  return new Filesystem(
4210
3990
  this,
@@ -4224,7 +4004,7 @@ var FilesystemClient = class {
4224
4004
  "fork and base filesystem names must not be empty"
4225
4005
  );
4226
4006
  }
4227
- await callNative(
4007
+ await callNative2(
4228
4008
  () => this.native.forkFilesystem(
4229
4009
  name,
4230
4010
  baseFilesystem,
@@ -4236,7 +4016,7 @@ var FilesystemClient = class {
4236
4016
  }
4237
4017
  /** Return a handle to an existing filesystem (verifies it exists). */
4238
4018
  async get(name) {
4239
- const traced = await callNative(
4019
+ const traced = await callNative2(
4240
4020
  () => this.native.filesystemMeta(name),
4241
4021
  new FilesystemNotFoundError(name)
4242
4022
  );
@@ -4254,7 +4034,7 @@ var FilesystemClient = class {
4254
4034
  }
4255
4035
  /** List all filesystems in the project. */
4256
4036
  async list() {
4257
- const traced = await callNative(() => this.native.listFilesystems());
4037
+ const traced = await callNative2(() => this.native.listFilesystems());
4258
4038
  const page = JSON.parse(traced.json);
4259
4039
  return (page.repos ?? []).map((repo) => ({
4260
4040
  name: String(repo.name ?? ""),
@@ -4265,7 +4045,7 @@ var FilesystemClient = class {
4265
4045
  }
4266
4046
  /** Permanently delete a filesystem and all its snapshots. */
4267
4047
  async delete(name) {
4268
- await callNative(
4048
+ await callNative2(
4269
4049
  () => this.native.deleteFilesystem(name),
4270
4050
  new FilesystemNotFoundError(name)
4271
4051
  );
@@ -4319,7 +4099,7 @@ var Filesystem = class {
4319
4099
  */
4320
4100
  async branch() {
4321
4101
  if (!this.defaultBranch) {
4322
- const traced = await callNative(
4102
+ const traced = await callNative2(
4323
4103
  () => this.native.filesystemMeta(this.name),
4324
4104
  new FilesystemNotFoundError(this.name)
4325
4105
  );
@@ -4374,7 +4154,7 @@ var Filesystem = class {
4374
4154
  const writes = entries.map(([path4, localPath]) => ({ path: path4, localPath }));
4375
4155
  const resolvedMessage = message || `write ${writes.length} local file(s) via SDK`;
4376
4156
  const branch = await this.branch();
4377
- const traced = await callNative(
4157
+ const traced = await callNative2(
4378
4158
  () => this.native.pushFilesystemPaths(
4379
4159
  this.name,
4380
4160
  writes,
@@ -4422,7 +4202,7 @@ var Filesystem = class {
4422
4202
  }
4423
4203
  async publishChanges(writes, deletes, moves, copies, message) {
4424
4204
  const branch = await this.branch();
4425
- const traced = await callNative(
4205
+ const traced = await callNative2(
4426
4206
  () => this.native.pushFilesystemFiles(
4427
4207
  this.name,
4428
4208
  writes,
@@ -4464,7 +4244,7 @@ var Filesystem = class {
4464
4244
  */
4465
4245
  async snapshot(message = "snapshot via SDK") {
4466
4246
  const resolvedMessage = message || "snapshot via SDK";
4467
- const traced = await callNative(
4247
+ const traced = await callNative2(
4468
4248
  () => this.native.retainFilesystemSnapshot(
4469
4249
  this.name,
4470
4250
  resolvedMessage,
@@ -4480,7 +4260,7 @@ var Filesystem = class {
4480
4260
  }
4481
4261
  /** List explicitly retained snapshots without reading filesystem contents. */
4482
4262
  async listSnapshots() {
4483
- const traced = await callNative(
4263
+ const traced = await callNative2(
4484
4264
  () => this.native.listFilesystemSnapshots(this.name),
4485
4265
  new FilesystemNotFoundError(this.name)
4486
4266
  );
@@ -4493,7 +4273,7 @@ var Filesystem = class {
4493
4273
  }
4494
4274
  /** Delete one permanent retention point; shared/head-reachable bytes remain. */
4495
4275
  async deleteSnapshot(snapshot) {
4496
- await callNative(
4276
+ await callNative2(
4497
4277
  () => this.native.deleteFilesystemSnapshot(this.name, snapshot),
4498
4278
  new FilesystemNotFoundError(this.name)
4499
4279
  );
@@ -4521,7 +4301,7 @@ var Filesystem = class {
4521
4301
  );
4522
4302
  }
4523
4303
  const resolvedVersion = options.version || await this.branch();
4524
- const traced = await callNative(
4304
+ const traced = await callNative2(
4525
4305
  () => this.native.readFilesystemFile(
4526
4306
  this.name,
4527
4307
  path4,
@@ -4552,7 +4332,7 @@ var Filesystem = class {
4552
4332
  /** List one directory (non-recursive) at `version`. */
4553
4333
  async listFiles(dirPath = "", version) {
4554
4334
  const resolvedVersion = version || await this.branch();
4555
- const traced = await callNative(
4335
+ const traced = await callNative2(
4556
4336
  () => this.native.listFilesystemTree(this.name, dirPath, resolvedVersion),
4557
4337
  new FileNotFoundInFilesystemError(this.name, dirPath || "/")
4558
4338
  );
@@ -4562,7 +4342,7 @@ var Filesystem = class {
4562
4342
  // -- status -------------------------------------------------------------------
4563
4343
  /** Remote status: identity plus the current native version. */
4564
4344
  async status() {
4565
- const metaTraced = await callNative(
4345
+ const metaTraced = await callNative2(
4566
4346
  () => this.native.filesystemMeta(this.name),
4567
4347
  new FilesystemNotFoundError(this.name)
4568
4348
  );
@@ -4572,7 +4352,7 @@ var Filesystem = class {
4572
4352
  let versionId = null;
4573
4353
  let generation = null;
4574
4354
  try {
4575
- const refTraced = await callNative(
4355
+ const refTraced = await callNative2(
4576
4356
  () => this.native.filesystemRefStatus(this.name, defaultBranch)
4577
4357
  );
4578
4358
  const ref = JSON.parse(refTraced.json);