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
@@ -44,12 +44,12 @@ var init_cjs_shims = __esm({
44
44
  });
45
45
 
46
46
  // src/defaults.ts
47
- var SDK_VERSION, API_URL, API_KEY, NAMESPACE, SANDBOX_PROXY_URL, DEFAULT_HTTP_TIMEOUT_MS, MAX_RETRIES, RETRY_BACKOFF_MS, RETRYABLE_STATUS_CODES;
47
+ var SDK_VERSION, API_URL, API_KEY, NAMESPACE, SANDBOX_PROXY_URL, DEFAULT_HTTP_TIMEOUT_MS, MAX_RETRIES, RETRY_BACKOFF_MS;
48
48
  var init_defaults = __esm({
49
49
  "src/defaults.ts"() {
50
50
  "use strict";
51
51
  init_cjs_shims();
52
- SDK_VERSION = "0.5.131";
52
+ SDK_VERSION = "0.5.133";
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";
@@ -57,33 +57,10 @@ var init_defaults = __esm({
57
57
  DEFAULT_HTTP_TIMEOUT_MS = 3e5;
58
58
  MAX_RETRIES = 3;
59
59
  RETRY_BACKOFF_MS = 500;
60
- RETRYABLE_STATUS_CODES = /* @__PURE__ */ new Set([429, 502, 503, 504]);
61
60
  }
62
61
  });
63
62
 
64
63
  // src/errors.ts
65
- function describeError(err) {
66
- const parts = [];
67
- const seen = /* @__PURE__ */ new Set();
68
- let current = err;
69
- for (let depth = 0; depth < 6; depth++) {
70
- if (current == null || typeof current !== "object" || seen.has(current)) {
71
- break;
72
- }
73
- seen.add(current);
74
- const e = current;
75
- const message = typeof e.message === "string" ? e.message.trim() : "";
76
- const code = typeof e.code === "string" ? e.code : void 0;
77
- let segment = message;
78
- if (code && (!message || !message.includes(code))) {
79
- segment = segment ? `${segment} (${code})` : code;
80
- }
81
- if (segment && !parts.includes(segment)) parts.push(segment);
82
- current = e.cause;
83
- }
84
- if (parts.length > 0) return parts.join(": ");
85
- return err instanceof Error ? err.message : String(err);
86
- }
87
64
  function formatErrorDetails(errorDetails) {
88
65
  if (errorDetails == null) return void 0;
89
66
  if (typeof errorDetails === "string") {
@@ -221,360 +198,464 @@ var init_errors = __esm({
221
198
  }
222
199
  });
223
200
 
224
- // src/sdk-timings.ts
225
- function sdkTimingsEnabled() {
226
- const value = process.env[SDK_TIMINGS_ENV_VAR];
227
- return value === "1" || value === "true" || value === "yes";
228
- }
229
- function sdkTimingPayloadsEnabled() {
230
- const value = process.env[SDK_TIMING_PAYLOADS_ENV_VAR];
231
- return value === "1" || value === "true" || value === "yes";
232
- }
233
- function nowMs() {
234
- return performance.now();
235
- }
236
- function logSdkTiming(op, phase, startedAt, fields = {}) {
237
- if (!sdkTimingsEnabled()) return;
238
- logSdkTimingEvent(op, phase, {
239
- ...fields,
240
- duration_ms: Math.round((nowMs() - startedAt) * 100) / 100
241
- });
242
- }
243
- function logSdkTimingEvent(op, phase, fields = {}) {
244
- if (!sdkTimingsEnabled()) return;
245
- const parts = [
246
- "[tensorlake:sdk-timing]",
247
- `op=${op}`,
248
- `phase=${phase}`
249
- ];
250
- for (const [key, value] of Object.entries(fields)) {
251
- if (value == null) continue;
252
- parts.push(`${key}=${formatSdkTimingValue(value)}`);
201
+ // src/native-worker-protocol.ts
202
+ var cancelNativeCall, closeNativeHandle;
203
+ var init_native_worker_protocol = __esm({
204
+ "src/native-worker-protocol.ts"() {
205
+ "use strict";
206
+ init_cjs_shims();
207
+ cancelNativeCall = /* @__PURE__ */ Symbol.for("tensorlake.native.cancel.v1");
208
+ closeNativeHandle = /* @__PURE__ */ Symbol.for("tensorlake.native.close.v1");
253
209
  }
254
- console.error(parts.join(" "));
210
+ });
211
+
212
+ // src/url.ts
213
+ function trimTrailingSlashes(url) {
214
+ return url.endsWith("/") ? url.slice(0, -1) : url;
255
215
  }
256
- function formatSdkTimingValue(value) {
257
- if (typeof value === "number" || typeof value === "boolean") {
258
- return String(value);
259
- }
260
- if (/^[A-Za-z0-9_./:@-]+$/.test(value)) {
261
- return value;
216
+ function resolveProxyTarget(proxyUrl, sandboxId) {
217
+ try {
218
+ const parsed = new URL(proxyUrl);
219
+ const host = parsed.hostname;
220
+ if (host === "localhost" || host === "127.0.0.1") {
221
+ return {
222
+ baseUrl: trimTrailingSlashes(proxyUrl),
223
+ hostHeader: `${sandboxId}.local`,
224
+ sandboxIdHeader: void 0
225
+ };
226
+ }
227
+ const port = parsed.port ? `:${parsed.port}` : "";
228
+ return {
229
+ baseUrl: `${parsed.protocol}//${host}${port}`,
230
+ hostHeader: void 0,
231
+ sandboxIdHeader: sandboxId
232
+ };
233
+ } catch {
234
+ return {
235
+ baseUrl: `${trimTrailingSlashes(proxyUrl)}/${sandboxId}`,
236
+ hostHeader: void 0,
237
+ sandboxIdHeader: void 0
238
+ };
262
239
  }
263
- return JSON.stringify(value);
264
240
  }
265
- var SDK_TIMINGS_ENV_VAR, SDK_TIMING_PAYLOADS_ENV_VAR;
266
- var init_sdk_timings = __esm({
267
- "src/sdk-timings.ts"() {
241
+ var init_url = __esm({
242
+ "src/url.ts"() {
268
243
  "use strict";
269
244
  init_cjs_shims();
270
- SDK_TIMINGS_ENV_VAR = "TENSORLAKE_SDK_TIMINGS";
271
- SDK_TIMING_PAYLOADS_ENV_VAR = "TENSORLAKE_SDK_TIMING_PAYLOADS";
245
+ init_defaults();
272
246
  }
273
247
  });
274
248
 
275
- // src/http.ts
276
- function withTraceId(value, traceId) {
277
- if (value == null) {
278
- return { traceId };
279
- }
280
- return Object.assign(value, { traceId });
249
+ // src/native-worker-client.ts
250
+ function createWorkerBinding(runtime) {
251
+ return {
252
+ NativeCloudClient: class {
253
+ constructor(...args) {
254
+ return runtime.handle("NativeCloudClient", args);
255
+ }
256
+ },
257
+ NativeSandboxClient: class {
258
+ constructor(...args) {
259
+ return runtime.handle("NativeSandboxClient", args);
260
+ }
261
+ },
262
+ NativeSandboxProxyClient: class {
263
+ constructor(...args) {
264
+ return runtime.handle("NativeSandboxProxyClient", args);
265
+ }
266
+ },
267
+ NativeRepositoryClient: class {
268
+ constructor(...args) {
269
+ return runtime.handle("NativeRepositoryClient", args);
270
+ }
271
+ },
272
+ validateManagedName: (name) => runtime.call(void 0, "validateManagedName", [name])
273
+ };
281
274
  }
282
- function hasHeader(headers, name) {
283
- const lowered = name.toLowerCase();
284
- return Object.keys(headers).some((key) => key.toLowerCase() === lowered);
275
+ function workerBinding() {
276
+ return createWorkerBinding(
277
+ runtimes[runtimeKey] ??= new NativeWorkerClient()
278
+ );
285
279
  }
286
- function normalizeRequestBody(body) {
287
- if (body == null) {
288
- return void 0;
289
- }
290
- if (body instanceof Uint8Array) {
291
- return Uint8Array.from(body).buffer;
292
- }
293
- return body;
280
+ function releaseNativeHandle(handle) {
281
+ handle?.[closeNativeHandle]?.();
294
282
  }
295
- function stripPathPayload(path3) {
296
- const queryStart = path3.search(/[?#]/);
297
- return queryStart === -1 ? path3 : path3.slice(0, queryStart);
283
+ var import_node_module, import_node_worker_threads, NativeWorkerClient, runtimeKey, runtimes;
284
+ var init_native_worker_client = __esm({
285
+ "src/native-worker-client.ts"() {
286
+ "use strict";
287
+ init_cjs_shims();
288
+ import_node_module = require("module");
289
+ import_node_worker_threads = require("worker_threads");
290
+ init_native_worker_protocol();
291
+ init_url();
292
+ NativeWorkerClient = class {
293
+ constructor(workerPath = () => (0, import_node_module.createRequire)(importMetaUrl).resolve(
294
+ "tensorlake/internal/native-worker"
295
+ )) {
296
+ this.workerPath = workerPath;
297
+ }
298
+ worker;
299
+ nextId = 1;
300
+ registered = /* @__PURE__ */ new Set();
301
+ pending = /* @__PURE__ */ new Map();
302
+ finalizers = new FinalizationRegistry(
303
+ (id) => this.release(id)
304
+ );
305
+ handle(kind, args, parent) {
306
+ const handle = { id: this.nextId++, kind, args, parent };
307
+ this.finalizers.register(handle, handle.id);
308
+ let closed = false;
309
+ return new Proxy(
310
+ {},
311
+ {
312
+ get: (_target, method) => {
313
+ if (method === "then") return void 0;
314
+ if (method === closeNativeHandle)
315
+ return () => {
316
+ closed = true;
317
+ this.release(handle.id);
318
+ };
319
+ if (method === "connectProxy")
320
+ return (...proxyArgs) => {
321
+ if (closed) throw new Error("Tensorlake native client is closed");
322
+ return this.handle("NativeSandboxProxyClient", proxyArgs, handle);
323
+ };
324
+ if (method === "baseUrl")
325
+ return () => resolveProxyTarget(String(args[0]), String(args[1])).baseUrl;
326
+ if (typeof method !== "string") return void 0;
327
+ return (...callArgs) => {
328
+ if (closed)
329
+ return Promise.reject(
330
+ new Error("Tensorlake native client is closed")
331
+ );
332
+ const emit = typeof callArgs.at(-1) === "function" ? callArgs.pop() : void 0;
333
+ return this.call(handle, method, callArgs, emit);
334
+ };
335
+ }
336
+ }
337
+ );
338
+ }
339
+ call(handle, method, args, emit) {
340
+ const id = this.nextId++;
341
+ let worker;
342
+ const promise = new Promise((resolve, reject) => {
343
+ try {
344
+ worker = this.getWorker();
345
+ this.pending.set(id, { resolve, reject, emit, handle });
346
+ worker.ref();
347
+ if (handle) this.register(handle, worker);
348
+ this.send(worker, {
349
+ type: "call",
350
+ id,
351
+ handleId: handle?.id,
352
+ method,
353
+ args,
354
+ stream: !!emit
355
+ });
356
+ } catch (error) {
357
+ this.pending.delete(id);
358
+ this.unrefIfIdle();
359
+ reject(error);
360
+ }
361
+ });
362
+ promise[cancelNativeCall] = () => {
363
+ const pending = this.pending.get(id);
364
+ if (pending && worker) {
365
+ pending.emit = void 0;
366
+ this.send(worker, { type: "cancel", id });
367
+ }
368
+ };
369
+ return promise;
370
+ }
371
+ getWorker() {
372
+ if (this.worker) return this.worker;
373
+ const worker = new import_node_worker_threads.Worker(this.workerPath(), {
374
+ // The bundled worker needs no application loaders or telemetry preloads.
375
+ // NODE_OPTIONS is parsed independently of execArgv by Node.
376
+ execArgv: [],
377
+ env: { ...process.env, NODE_OPTIONS: "" },
378
+ name: "tensorlake-native"
379
+ });
380
+ this.worker = worker;
381
+ worker.on("message", (message) => {
382
+ const pending = this.pending.get(message.id);
383
+ if (!pending || this.worker !== worker) return;
384
+ if (message.type === "event") {
385
+ Promise.resolve().then(() => pending.emit?.(message.value)).then(
386
+ () => {
387
+ if (this.worker === worker)
388
+ this.send(worker, { type: "ack", id: message.id });
389
+ },
390
+ (error) => {
391
+ this.send(worker, { type: "cancel", id: message.id });
392
+ pending.reject(error);
393
+ }
394
+ );
395
+ return;
396
+ }
397
+ this.pending.delete(message.id);
398
+ if (message.type === "error") {
399
+ const error = new Error(message.error.message);
400
+ error.name = message.error.name;
401
+ error.stack = message.error.stack ?? error.stack;
402
+ pending.reject(error);
403
+ } else {
404
+ pending.resolve(message.value);
405
+ }
406
+ this.unrefIfIdle();
407
+ });
408
+ const fail = (error) => {
409
+ if (this.worker !== worker) return;
410
+ this.worker = void 0;
411
+ this.registered.clear();
412
+ for (const pending of this.pending.values()) pending.reject(error);
413
+ this.pending.clear();
414
+ void worker.terminate();
415
+ };
416
+ worker.on("error", fail);
417
+ worker.on("messageerror", fail);
418
+ worker.on(
419
+ "exit",
420
+ (code) => fail(
421
+ new Error(
422
+ `Tensorlake native worker exited (${code}); in-flight operations were not retried`
423
+ )
424
+ )
425
+ );
426
+ worker.unref();
427
+ return worker;
428
+ }
429
+ register(handle, worker) {
430
+ if (this.registered.has(handle.id)) return;
431
+ if (handle.parent) this.register(handle.parent, worker);
432
+ this.send(worker, {
433
+ type: "create",
434
+ handle: { id: handle.id, kind: handle.kind, args: handle.args },
435
+ parentId: handle.parent?.id
436
+ });
437
+ this.registered.add(handle.id);
438
+ }
439
+ release(handleId) {
440
+ if (this.worker && this.registered.delete(handleId))
441
+ this.send(this.worker, { type: "release", handleId });
442
+ }
443
+ send(worker, message) {
444
+ worker.postMessage(message);
445
+ }
446
+ unrefIfIdle() {
447
+ if (this.pending.size === 0) this.worker?.unref();
448
+ }
449
+ };
450
+ runtimeKey = /* @__PURE__ */ Symbol.for(
451
+ `tensorlake.native.worker.${false ? "source" : "0.5.133"}.v1`
452
+ );
453
+ runtimes = globalThis;
454
+ }
455
+ });
456
+
457
+ // src/native-sandbox.ts
458
+ function loadNativeSandboxBinding() {
459
+ return cachedBinding ??= workerBinding();
298
460
  }
299
- function throwMappedError(status, body, path3) {
300
- let message = body;
461
+ function parseNativeError(error) {
462
+ const message = error instanceof Error ? error.message : typeof error === "string" ? error : "";
463
+ if (!message) return null;
301
464
  try {
302
- const parsed = JSON.parse(body);
303
- if (parsed.message) message = parsed.message;
304
- else if (parsed.error) message = parsed.error;
465
+ const parsed = JSON.parse(message);
466
+ if (parsed && typeof parsed.category === "string") {
467
+ return {
468
+ category: parsed.category,
469
+ status: typeof parsed.status === "number" ? parsed.status : null,
470
+ message: typeof parsed.message === "string" ? parsed.message : message
471
+ };
472
+ }
305
473
  } catch {
306
474
  }
475
+ return null;
476
+ }
477
+ function translateNativeError(error, context) {
478
+ const payload = parseNativeError(error);
479
+ if (!payload) {
480
+ if (error instanceof Error) return error;
481
+ return new SandboxError(String(error));
482
+ }
483
+ const { category, status, message } = payload;
484
+ if (category === "connection") {
485
+ return new SandboxConnectionError(message, { cause: error });
486
+ }
307
487
  if (status === 404) {
308
- if (path3.includes("sandbox-pools") || path3.includes("pools")) {
309
- const match = path3.match(/sandbox-pools\/([^/]+)/);
310
- if (match) throw new PoolNotFoundError(match[1]);
488
+ if (context?.notFoundKind === "pool" && context.poolId) {
489
+ return new PoolNotFoundError(context.poolId);
311
490
  }
312
- if (path3.includes("sandboxes")) {
313
- const match = path3.match(/sandboxes\/([^/]+)/);
314
- if (match) throw new SandboxNotFoundError(match[1]);
491
+ if (context?.notFoundKind === "sandbox" && context.sandboxId) {
492
+ return new SandboxNotFoundError(context.sandboxId);
315
493
  }
316
- throw new RemoteAPIError(404, message);
494
+ return new RemoteAPIError(404, message);
317
495
  }
318
- if (status === 409) {
319
- if (path3.includes("sandbox-pools") || path3.includes("pools")) {
320
- const match = path3.match(/sandbox-pools\/([^/]+)/);
321
- if (match) throw new PoolInUseError(match[1], message);
322
- }
496
+ if (status === 409 && context?.poolId) {
497
+ return new PoolInUseError(context.poolId, message);
323
498
  }
324
- throw new RemoteAPIError(status, message);
499
+ if (typeof status === "number") {
500
+ return new RemoteAPIError(status, message);
501
+ }
502
+ return new SandboxError(message);
325
503
  }
326
- function anySignal(signals) {
327
- const controller = new AbortController();
328
- for (const signal of signals) {
329
- if (signal.aborted) {
330
- controller.abort(signal.reason);
331
- return controller.signal;
332
- }
333
- signal.addEventListener("abort", () => controller.abort(signal.reason), {
334
- once: true
504
+ async function callNative(fn, context) {
505
+ try {
506
+ return await fn();
507
+ } catch (error) {
508
+ throw translateNativeError(error, context);
509
+ }
510
+ }
511
+ async function* nativeEventStream(start, context, signal) {
512
+ if (signal?.aborted) return;
513
+ const queue = [];
514
+ let wake;
515
+ let finished = false;
516
+ let stopped = false;
517
+ let failure;
518
+ const notify = () => {
519
+ const resolve = wake;
520
+ wake = void 0;
521
+ resolve?.();
522
+ };
523
+ const emit = (value) => {
524
+ if (stopped) return Promise.resolve();
525
+ return new Promise((consumed) => {
526
+ queue.push({ value, consumed });
527
+ notify();
528
+ });
529
+ };
530
+ let call;
531
+ const onAbort = () => {
532
+ stopped = true;
533
+ call?.[cancelNativeCall]?.();
534
+ notify();
535
+ };
536
+ signal?.addEventListener("abort", onAbort, { once: true });
537
+ try {
538
+ call = start(emit);
539
+ void call.catch((error) => {
540
+ failure = error;
541
+ }).finally(() => {
542
+ finished = true;
543
+ notify();
335
544
  });
545
+ while (!stopped) {
546
+ const event = queue.shift();
547
+ if (event) {
548
+ try {
549
+ yield JSON.parse(event.value);
550
+ } finally {
551
+ event.consumed();
552
+ }
553
+ } else if (finished) {
554
+ break;
555
+ } else {
556
+ await new Promise((resolve) => {
557
+ wake = resolve;
558
+ });
559
+ }
560
+ }
561
+ if (!stopped && failure !== void 0) throw translateNativeError(failure, context);
562
+ } finally {
563
+ stopped = true;
564
+ signal?.removeEventListener("abort", onAbort);
565
+ call?.[cancelNativeCall]?.();
566
+ for (const event of queue) event.consumed();
336
567
  }
337
- return controller.signal;
338
- }
339
- function sleep(ms) {
340
- return new Promise((resolve) => setTimeout(resolve, ms));
341
568
  }
342
- var import_undici, REQUEST_TIMEOUT_HEADER, HttpClient;
343
- var init_http = __esm({
344
- "src/http.ts"() {
569
+ var cachedBinding;
570
+ var init_native_sandbox = __esm({
571
+ "src/native-sandbox.ts"() {
345
572
  "use strict";
346
573
  init_cjs_shims();
347
- import_undici = require("undici");
348
- init_defaults();
349
574
  init_errors();
350
- init_sdk_timings();
351
- REQUEST_TIMEOUT_HEADER = "X-Tensorlake-Request-Timeout-Ms";
352
- (0, import_undici.setGlobalDispatcher)(
353
- new import_undici.Agent({
354
- keepAliveTimeout: 6e4,
355
- allowH2: true
356
- })
357
- );
358
- HttpClient = class _HttpClient {
359
- baseUrl;
360
- headers;
361
- maxRetries;
362
- retryBackoffMs;
363
- timeoutMs;
364
- abortController = null;
575
+ init_native_worker_client();
576
+ init_native_worker_protocol();
577
+ }
578
+ });
579
+
580
+ // src/native-cloud.ts
581
+ async function serializeRequest(method, path3, options) {
582
+ const headers = { ...options?.headers };
583
+ let body = options?.body;
584
+ if (options?.json !== void 0) {
585
+ body = JSON.stringify(options.json);
586
+ if (!Object.keys(headers).some((key) => key.toLowerCase() === "content-type")) {
587
+ headers["Content-Type"] = "application/json";
588
+ }
589
+ }
590
+ const request = {
591
+ method,
592
+ path: path3,
593
+ headersJson: JSON.stringify(headers),
594
+ statusOnlyCodes: [...options?.statusOnlyCodes ?? []]
595
+ };
596
+ if (body instanceof FormData) {
597
+ request.parts = [];
598
+ for (const [name, value] of body.entries()) {
599
+ 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" });
600
+ }
601
+ } else if (body !== void 0) {
602
+ if (body instanceof Blob) request.body = Buffer.from(await body.arrayBuffer());
603
+ else if (typeof body === "string") request.body = Buffer.from(body);
604
+ else if (body instanceof ArrayBuffer) request.body = Buffer.from(new Uint8Array(body));
605
+ else request.body = Buffer.from(body);
606
+ }
607
+ return request;
608
+ }
609
+ var NativeCloudTransport;
610
+ var init_native_cloud = __esm({
611
+ "src/native-cloud.ts"() {
612
+ "use strict";
613
+ init_cjs_shims();
614
+ init_native_sandbox();
615
+ init_native_worker_client();
616
+ NativeCloudTransport = class {
365
617
  constructor(options) {
366
- const url = options.baseUrl;
367
- this.baseUrl = url.endsWith("/") ? url.slice(0, -1) : url;
368
- this.maxRetries = options.maxRetries ?? MAX_RETRIES;
369
- this.retryBackoffMs = options.retryBackoffMs ?? RETRY_BACKOFF_MS;
370
- this.timeoutMs = options.timeoutMs === void 0 ? DEFAULT_HTTP_TIMEOUT_MS : options.timeoutMs;
371
- this.headers = {
372
- "User-Agent": `tensorlake-typescript-sdk/${SDK_VERSION}`
373
- };
374
- if (this.timeoutMs != null) {
375
- this.headers[REQUEST_TIMEOUT_HEADER] = String(this.timeoutMs);
376
- }
377
- if (options.apiKey) {
378
- this.headers["Authorization"] = `Bearer ${options.apiKey}`;
618
+ this.options = options;
619
+ if (!Number.isSafeInteger(options.maxRetries) || options.maxRetries < 0 || options.maxRetries > 4294967295) {
620
+ throw new RangeError("maxRetries must be a non-negative 32-bit integer");
379
621
  }
380
- if (options.organizationId) {
381
- this.headers["X-Forwarded-Organization-Id"] = options.organizationId;
382
- }
383
- if (options.projectId) {
384
- this.headers["X-Forwarded-Project-Id"] = options.projectId;
385
- }
386
- if (options.hostHeader) {
387
- this.headers["Host"] = options.hostHeader;
388
- }
389
- if (options.sandboxIdHeader) {
390
- this.headers["X-Tensorlake-Sandbox-Id"] = options.sandboxIdHeader;
391
- }
392
- if (options.routingHint) {
393
- this.headers["X-Tensorlake-Route-Hint"] = options.routingHint;
622
+ if (!Number.isFinite(options.retryBackoffMs) || options.retryBackoffMs < 0) {
623
+ throw new RangeError("retryBackoffMs must be a non-negative finite number");
394
624
  }
395
625
  }
396
- close() {
397
- this.abortController?.abort();
398
- this.abortController = null;
626
+ native;
627
+ closed = false;
628
+ client() {
629
+ if (this.closed) throw new Error("Tensorlake native client is closed");
630
+ if (this.native) return this.native;
631
+ const ctor = loadNativeSandboxBinding().NativeCloudClient;
632
+ if (!ctor) throw new Error("Native binding does not export NativeCloudClient; rebuild with 'npm run build:native'");
633
+ return this.native = new ctor(JSON.stringify(this.options));
399
634
  }
400
- /** Make a JSON request, returning the parsed response body. */
401
- async requestJson(method, path3, options) {
402
- const response = await this.requestResponse(method, path3, {
403
- json: options?.body,
404
- headers: options?.headers,
405
- signal: options?.signal,
406
- retryableStatusCodes: options?.retryableStatusCodes,
407
- allowedErrorStatusCodes: options?.allowedErrorStatusCodes,
408
- allowHttpErrors: options?.allowHttpErrors
409
- });
410
- const text = await response.text();
411
- const data = text ? JSON.parse(text) : void 0;
412
- return withTraceId(data, response.traceId);
413
- }
414
- /** Make a request returning raw bytes. */
415
- async requestBytes(method, path3, options) {
416
- const headers = { ...options?.headers ?? {} };
417
- if (options?.contentType) {
418
- headers["Content-Type"] = options.contentType;
419
- }
420
- const response = await this.requestResponse(method, path3, {
421
- body: options?.body,
422
- headers,
423
- signal: options?.signal
424
- });
425
- const buffer = await response.arrayBuffer();
426
- return withTraceId(new Uint8Array(buffer), response.traceId);
427
- }
428
- /** Make a request and return the response body as an SSE stream. */
429
- async requestStream(method, path3, options) {
430
- const response = await this.requestResponse(method, path3, {
431
- json: options?.json,
432
- headers: { Accept: "text/event-stream" },
433
- signal: options?.signal
434
- });
435
- if (!response.body) {
436
- throw new RemoteAPIError(
437
- response.status,
438
- "No response body for SSE stream"
439
- );
440
- }
441
- return withTraceId(response.body, response.traceId);
635
+ close() {
636
+ this.closed = true;
637
+ releaseNativeHandle(this.native ?? null);
638
+ this.native = void 0;
442
639
  }
443
- /** Make a request and return the raw Response. */
444
640
  async requestResponse(method, path3, options) {
445
- const headers = {
446
- ...this.headers,
447
- ...options?.headers ?? {}
448
- };
449
- const hasJsonBody = options?.json !== void 0;
450
- if (hasJsonBody && !hasHeader(headers, "Content-Type")) {
451
- headers["Content-Type"] = "application/json";
452
- }
453
- const body = hasJsonBody ? JSON.stringify(options?.json) : normalizeRequestBody(options?.body);
454
- const { response, traceId } = await this.doFetch(
455
- method,
456
- path3,
457
- body,
458
- headers,
459
- options?.signal,
460
- options?.allowHttpErrors ?? false,
461
- options?.retryableStatusCodes ?? RETRYABLE_STATUS_CODES,
462
- options?.allowedErrorStatusCodes ?? /* @__PURE__ */ new Set()
641
+ const request = await serializeRequest(method, path3, options);
642
+ const raw = await callNative(() => this.client().request(request));
643
+ const response = new Response(
644
+ [204, 205, 304].includes(raw.status) ? null : Uint8Array.from(raw.data).buffer,
645
+ { status: raw.status, headers: JSON.parse(raw.headersJson) }
463
646
  );
464
- return withTraceId(response, traceId);
647
+ return Object.assign(response, { traceId: raw.traceId });
465
648
  }
466
- static makeTraceparent() {
467
- const randomHex = (bytes) => Array.from(crypto.getRandomValues(new Uint8Array(bytes))).map((b) => b.toString(16).padStart(2, "0")).join("");
468
- const traceId = randomHex(16);
469
- const spanId = randomHex(8);
470
- return { traceparent: `00-${traceId}-${spanId}-01`, traceId };
649
+ async requestJson(method, path3) {
650
+ const response = await this.requestResponse(method, path3);
651
+ const text = await response.text();
652
+ const value = text ? JSON.parse(text) : null;
653
+ return Object.assign(value ?? {}, { traceId: response.traceId });
471
654
  }
472
- async doFetch(method, path3, body, headers, signal, allowHttpErrors = false, retryableStatusCodes = RETRYABLE_STATUS_CODES, allowedErrorStatusCodes = /* @__PURE__ */ new Set()) {
473
- const url = `${this.baseUrl}${path3}`;
474
- const { traceparent, traceId } = _HttpClient.makeTraceparent();
475
- headers["traceparent"] = traceparent;
476
- let lastError;
477
- const operationStart = nowMs();
478
- const timingPath = sdkTimingPayloadsEnabled() ? path3 : stripPathPayload(path3);
479
- for (let attempt = 0; attempt <= this.maxRetries; attempt++) {
480
- if (attempt > 0) {
481
- const delay = this.retryBackoffMs * Math.pow(2, attempt - 1);
482
- logSdkTimingEvent("http.request", "retry_sleep_start", {
483
- method,
484
- path: timingPath,
485
- attempt,
486
- delay_ms: delay,
487
- server_trace_id: traceId
488
- });
489
- await sleep(delay);
490
- }
491
- this.abortController = new AbortController();
492
- let timedOut = false;
493
- const timeoutId = this.timeoutMs == null ? null : setTimeout(() => {
494
- timedOut = true;
495
- this.abortController?.abort();
496
- }, this.timeoutMs);
497
- const combinedSignal = signal ? anySignal([signal, this.abortController.signal]) : this.abortController.signal;
498
- const attemptStart = nowMs();
499
- try {
500
- const response = await (0, import_undici.fetch)(url, {
501
- method,
502
- headers,
503
- body,
504
- signal: combinedSignal
505
- });
506
- if (timeoutId != null) clearTimeout(timeoutId);
507
- logSdkTiming("http.request", "headers", attemptStart, {
508
- method,
509
- path: timingPath,
510
- status: response.status,
511
- attempt,
512
- server_trace_id: traceId
513
- });
514
- if (response.ok) {
515
- logSdkTiming("http.request", "complete", operationStart, {
516
- method,
517
- path: timingPath,
518
- status: response.status,
519
- attempts: attempt + 1,
520
- server_trace_id: traceId
521
- });
522
- return { response, traceId };
523
- }
524
- if (retryableStatusCodes.has(response.status) && attempt < this.maxRetries) {
525
- lastError = new RemoteAPIError(
526
- response.status,
527
- await response.text().catch(() => "")
528
- );
529
- logSdkTimingEvent("http.request", "retryable_status", {
530
- method,
531
- path: timingPath,
532
- status: response.status,
533
- attempt,
534
- server_trace_id: traceId
535
- });
536
- continue;
537
- }
538
- if (allowHttpErrors || allowedErrorStatusCodes.has(response.status)) {
539
- logSdkTiming("http.request", "complete", operationStart, {
540
- method,
541
- path: timingPath,
542
- status: response.status,
543
- attempts: attempt + 1,
544
- server_trace_id: traceId
545
- });
546
- return { response, traceId };
547
- }
548
- const errorBody = await response.text().catch(() => "");
549
- throwMappedError(response.status, errorBody, path3);
550
- } catch (err) {
551
- if (timeoutId != null) clearTimeout(timeoutId);
552
- if (err instanceof RemoteAPIError || err instanceof SandboxNotFoundError || err instanceof PoolNotFoundError || err instanceof PoolInUseError) {
553
- throw err;
554
- }
555
- if (signal?.aborted && !timedOut) {
556
- throw new SandboxConnectionError("request aborted by caller", {
557
- cause: err
558
- });
559
- }
560
- lastError = err instanceof Error ? err : new Error(String(err));
561
- logSdkTiming("http.request", "error", attemptStart, {
562
- method,
563
- path: timingPath,
564
- attempt,
565
- server_trace_id: traceId,
566
- error: timedOut ? `request timed out after ${this.timeoutMs}ms` : describeError(err)
567
- });
568
- if (attempt >= this.maxRetries) {
569
- const detail = timedOut ? `request timed out after ${this.timeoutMs}ms` : describeError(err);
570
- throw new SandboxConnectionError(detail, { cause: err });
571
- }
572
- }
573
- }
574
- throw new SandboxConnectionError(
575
- lastError ? describeError(lastError) : "request failed",
576
- { cause: lastError }
577
- );
655
+ async *stream(method, path3, signal) {
656
+ if (signal?.aborted) return;
657
+ const request = await serializeRequest(method, path3, { headers: { Accept: "text/event-stream" } });
658
+ yield* nativeEventStream((emit) => this.client().stream(request, emit), void 0, signal);
578
659
  }
579
660
  };
580
661
  }
@@ -630,65 +711,6 @@ var init_models = __esm({
630
711
  }
631
712
  });
632
713
 
633
- // src/sse.ts
634
- async function* parseSSEMessages(stream, signal) {
635
- const reader = stream.getReader();
636
- const decoder = new TextDecoder();
637
- let buffer = "";
638
- try {
639
- while (true) {
640
- if (signal?.aborted) break;
641
- const { done, value } = await reader.read();
642
- if (done) break;
643
- buffer += decoder.decode(value, { stream: true });
644
- const parts = buffer.split(/\r?\n\r?\n/);
645
- buffer = parts.pop() ?? "";
646
- for (const part of parts) {
647
- const lines = part.split(/\r?\n/);
648
- const dataLines = [];
649
- let event;
650
- let id;
651
- for (const line of lines) {
652
- if (!line || line.startsWith(":")) continue;
653
- const separator = line.indexOf(":");
654
- const field = separator === -1 ? line : line.slice(0, separator);
655
- let value2 = separator === -1 ? "" : line.slice(separator + 1);
656
- if (value2.startsWith(" ")) {
657
- value2 = value2.slice(1);
658
- }
659
- if (field === "data") {
660
- dataLines.push(value2);
661
- } else if (field === "event") {
662
- event = value2;
663
- } else if (field === "id") {
664
- id = value2;
665
- }
666
- }
667
- if (dataLines.length > 0 || event || id) {
668
- yield { data: dataLines.join("\n"), event, id };
669
- }
670
- }
671
- }
672
- } finally {
673
- reader.releaseLock();
674
- }
675
- }
676
- async function* parseSSEStream(stream, signal) {
677
- for await (const message of parseSSEMessages(stream, signal)) {
678
- if (!message.data) continue;
679
- try {
680
- yield JSON.parse(message.data);
681
- } catch {
682
- }
683
- }
684
- }
685
- var init_sse = __esm({
686
- "src/sse.ts"() {
687
- "use strict";
688
- init_cjs_shims();
689
- }
690
- });
691
-
692
714
  // src/cloud-client.ts
693
715
  function secretFromMetadata(metadata) {
694
716
  return {
@@ -750,7 +772,7 @@ function createApplicationBuildForm(request, imageContexts) {
750
772
  }
751
773
  return form;
752
774
  }
753
- function trimTrailingSlashes(value) {
775
+ function trimTrailingSlashes2(value) {
754
776
  return value.endsWith("/") ? value.slice(0, -1) : value;
755
777
  }
756
778
  function nextRequestPath(next) {
@@ -788,11 +810,10 @@ var init_cloud_client = __esm({
788
810
  init_cjs_shims();
789
811
  import_nanoid = require("nanoid");
790
812
  init_defaults();
791
- init_http();
813
+ init_native_cloud();
792
814
  init_models();
793
- init_sse();
794
815
  CloudClient = class _CloudClient {
795
- http;
816
+ transport;
796
817
  organizationId;
797
818
  projectId;
798
819
  namespace;
@@ -800,20 +821,22 @@ var init_cloud_client = __esm({
800
821
  this.organizationId = options?.organizationId;
801
822
  this.projectId = options?.projectId;
802
823
  this.namespace = options?.namespace ?? NAMESPACE;
803
- this.http = new HttpClient({
824
+ this.transport = new NativeCloudTransport({
804
825
  baseUrl: options?.apiUrl ?? API_URL,
805
826
  apiKey: options?.apiKey ?? API_KEY,
806
827
  organizationId: this.organizationId,
807
828
  projectId: this.projectId,
808
829
  maxRetries: options?.maxRetries ?? MAX_RETRIES,
809
- retryBackoffMs: options?.retryBackoffMs ?? RETRY_BACKOFF_MS
830
+ retryBackoffMs: options?.retryBackoffMs ?? RETRY_BACKOFF_MS,
831
+ timeoutMs: DEFAULT_HTTP_TIMEOUT_MS,
832
+ userAgent: `tensorlake-typescript-sdk/${SDK_VERSION}`
810
833
  });
811
834
  }
812
835
  static forCloud(options) {
813
836
  return new _CloudClient(options);
814
837
  }
815
838
  close() {
816
- this.http.close();
839
+ this.transport.close();
817
840
  }
818
841
  async upsertApplication(manifest, codeZip, upgradeRunningRequests = false) {
819
842
  const applicationManifest = { ...manifest };
@@ -841,18 +864,18 @@ var init_cloud_client = __esm({
841
864
  "upgrade_requests_to_latest_code",
842
865
  String(upgradeRunningRequests)
843
866
  );
844
- await this.http.requestResponse("POST", this.namespacePath("applications"), {
867
+ await this.transport.requestResponse("POST", this.namespacePath("applications"), {
845
868
  body: form
846
869
  });
847
870
  }
848
871
  async deleteApplication(applicationName) {
849
- await this.http.requestResponse(
872
+ await this.transport.requestResponse(
850
873
  "DELETE",
851
874
  this.namespacePath(`applications/${encodeURIComponent(applicationName)}`)
852
875
  );
853
876
  }
854
877
  async deleteSandboxImage(imageName) {
855
- await this.http.requestResponse(
878
+ await this.transport.requestResponse(
856
879
  "DELETE",
857
880
  this.namespacePath(`sandbox-images/${encodeURIComponent(imageName)}`)
858
881
  );
@@ -871,10 +894,10 @@ var init_cloud_client = __esm({
871
894
  options?.organizationId,
872
895
  options?.projectId
873
896
  );
874
- const response = await this.http.requestResponse(
897
+ const response = await this.transport.requestResponse(
875
898
  "GET",
876
899
  `${base}/by-name/${encodeURIComponent(imageName)}`,
877
- { allowedErrorStatusCodes: /* @__PURE__ */ new Set([404]) }
900
+ { statusOnlyCodes: /* @__PURE__ */ new Set([404]) }
878
901
  );
879
902
  if (response.status === 404) {
880
903
  return null;
@@ -896,7 +919,7 @@ var init_cloud_client = __esm({
896
919
  let path3 = `${base}?pageSize=100`;
897
920
  const templates = [];
898
921
  while (path3 !== null) {
899
- const page = await this.http.requestJson(
922
+ const page = await this.transport.requestJson(
900
923
  "GET",
901
924
  path3
902
925
  );
@@ -909,7 +932,7 @@ var init_cloud_client = __esm({
909
932
  return templates;
910
933
  }
911
934
  async applications() {
912
- const raw = await this.http.requestJson(
935
+ const raw = await this.transport.requestJson(
913
936
  "GET",
914
937
  this.namespacePath("applications")
915
938
  );
@@ -918,7 +941,7 @@ var init_cloud_client = __esm({
918
941
  );
919
942
  }
920
943
  async applicationManifest(applicationName) {
921
- const raw = await this.http.requestJson(
944
+ const raw = await this.transport.requestJson(
922
945
  "GET",
923
946
  this.namespacePath(`applications/${encodeURIComponent(applicationName)}`)
924
947
  );
@@ -928,10 +951,10 @@ var init_cloud_client = __esm({
928
951
  const path3 = this.namespacePath(
929
952
  `applications/${encodeURIComponent(applicationName)}`
930
953
  );
931
- const response = inputs.length === 0 ? await this.http.requestResponse("POST", path3, {
954
+ const response = inputs.length === 0 ? await this.transport.requestResponse("POST", path3, {
932
955
  body: new Uint8Array(),
933
956
  headers: { Accept: "application/json" }
934
- }) : inputs.length === 1 && inputs[0].name === "0" ? await this.http.requestResponse("POST", path3, {
957
+ }) : inputs.length === 1 && inputs[0].name === "0" ? await this.transport.requestResponse("POST", path3, {
935
958
  body: toRequestBody(inputs[0].data),
936
959
  headers: {
937
960
  Accept: "application/json",
@@ -946,13 +969,13 @@ var init_cloud_client = __esm({
946
969
  return requestId;
947
970
  }
948
971
  async waitOnRequestCompletion(applicationName, requestId) {
949
- const stream = await this.http.requestStream(
972
+ const stream = this.transport.stream(
950
973
  "GET",
951
974
  this.namespacePath(
952
975
  `applications/${encodeURIComponent(applicationName)}/requests/${encodeURIComponent(requestId)}/progress`
953
976
  )
954
977
  );
955
- for await (const event of parseSSEStream(stream)) {
978
+ for await (const event of stream) {
956
979
  if (Object.prototype.hasOwnProperty.call(event, "RequestFinished")) {
957
980
  return;
958
981
  }
@@ -960,7 +983,7 @@ var init_cloud_client = __esm({
960
983
  throw new Error("progress stream ended before request completion");
961
984
  }
962
985
  async requestMetadata(applicationName, requestId) {
963
- const raw = await this.http.requestJson(
986
+ const raw = await this.transport.requestJson(
964
987
  "GET",
965
988
  this.namespacePath(
966
989
  `applications/${encodeURIComponent(applicationName)}/requests/${encodeURIComponent(requestId)}`
@@ -969,7 +992,7 @@ var init_cloud_client = __esm({
969
992
  return fromSnakeKeys(raw);
970
993
  }
971
994
  async requestOutput(applicationName, requestId) {
972
- const response = await this.http.requestResponse(
995
+ const response = await this.transport.requestResponse(
973
996
  "GET",
974
997
  this.namespacePath(
975
998
  `applications/${encodeURIComponent(applicationName)}/requests/${encodeURIComponent(requestId)}/output`
@@ -987,7 +1010,7 @@ var init_cloud_client = __esm({
987
1010
  options?.organizationId,
988
1011
  options?.projectId
989
1012
  );
990
- const raw = await this.http.requestJson("GET", base);
1013
+ const raw = await this.transport.requestJson("GET", base);
991
1014
  const pageSize = Math.max(0, options?.pageSize ?? 100);
992
1015
  return Object.assign(
993
1016
  {
@@ -1002,7 +1025,7 @@ var init_cloud_client = __esm({
1002
1025
  options?.organizationId,
1003
1026
  options?.projectId
1004
1027
  );
1005
- const raw = await this.http.requestJson(
1028
+ const raw = await this.transport.requestJson(
1006
1029
  "GET",
1007
1030
  `${base}/${encodeURIComponent(secretId)}`
1008
1031
  );
@@ -1027,24 +1050,24 @@ var init_cloud_client = __esm({
1027
1050
  options?.organizationId,
1028
1051
  options?.projectId
1029
1052
  );
1030
- await this.http.requestResponse(
1053
+ await this.transport.requestResponse(
1031
1054
  "DELETE",
1032
1055
  `${base}/${encodeURIComponent(secretId)}`
1033
1056
  );
1034
1057
  }
1035
1058
  async upsertSecret(base, secret) {
1036
- let response = await this.http.requestResponse("POST", base, {
1059
+ let response = await this.transport.requestResponse("POST", base, {
1037
1060
  json: secret,
1038
1061
  headers: { "Idempotency-Key": (0, import_nanoid.nanoid)() },
1039
- allowedErrorStatusCodes: /* @__PURE__ */ new Set([409])
1062
+ statusOnlyCodes: /* @__PURE__ */ new Set([409])
1040
1063
  });
1041
1064
  if (response.status === 409) {
1042
1065
  const prefix = base.slice(0, -"/secrets".length);
1043
- const existing = await this.http.requestJson(
1066
+ const existing = await this.transport.requestJson(
1044
1067
  "GET",
1045
1068
  `${prefix}/secret-names/${encodeURIComponent(secret.name)}`
1046
1069
  );
1047
- response = await this.http.requestResponse(
1070
+ response = await this.transport.requestResponse(
1048
1071
  "POST",
1049
1072
  `${base}/${encodeURIComponent(existing.id)}/versions`,
1050
1073
  {
@@ -1070,9 +1093,9 @@ var init_cloud_client = __esm({
1070
1093
  new Blob([toBlobPart(request.buildContext)]),
1071
1094
  "context.tar.gz"
1072
1095
  );
1073
- const response = await this.http.requestResponse(
1096
+ const response = await this.transport.requestResponse(
1074
1097
  "PUT",
1075
- `${trimTrailingSlashes(buildServicePath)}/builds`,
1098
+ `${trimTrailingSlashes2(buildServicePath)}/builds`,
1076
1099
  { body: form }
1077
1100
  );
1078
1101
  const raw = await parseJsonResponse(response);
@@ -1080,48 +1103,48 @@ var init_cloud_client = __esm({
1080
1103
  }
1081
1104
  async createApplicationBuild(buildServicePath, request, imageContexts) {
1082
1105
  const form = createApplicationBuildForm(request, imageContexts);
1083
- const response = await this.http.requestResponse(
1106
+ const response = await this.transport.requestResponse(
1084
1107
  "POST",
1085
- trimTrailingSlashes(buildServicePath),
1108
+ trimTrailingSlashes2(buildServicePath),
1086
1109
  { body: form }
1087
1110
  );
1088
1111
  const raw = await parseJsonResponse(response);
1089
1112
  return fromSnakeKeys(raw);
1090
1113
  }
1091
1114
  async applicationBuildInfo(buildServicePath, applicationBuildId) {
1092
- const raw = await this.http.requestJson(
1115
+ const raw = await this.transport.requestJson(
1093
1116
  "GET",
1094
- `${trimTrailingSlashes(buildServicePath)}/${encodeURIComponent(applicationBuildId)}`
1117
+ `${trimTrailingSlashes2(buildServicePath)}/${encodeURIComponent(applicationBuildId)}`
1095
1118
  );
1096
1119
  return fromSnakeKeys(raw);
1097
1120
  }
1098
1121
  async cancelApplicationBuild(buildServicePath, applicationBuildId) {
1099
- const raw = await this.http.requestJson(
1122
+ const raw = await this.transport.requestJson(
1100
1123
  "POST",
1101
- `${trimTrailingSlashes(buildServicePath)}/${encodeURIComponent(applicationBuildId)}/cancel`
1124
+ `${trimTrailingSlashes2(buildServicePath)}/${encodeURIComponent(applicationBuildId)}/cancel`
1102
1125
  );
1103
1126
  return fromSnakeKeys(raw);
1104
1127
  }
1105
1128
  async buildInfo(buildServicePath, buildId) {
1106
- const raw = await this.http.requestJson(
1129
+ const raw = await this.transport.requestJson(
1107
1130
  "GET",
1108
- `${trimTrailingSlashes(buildServicePath)}/builds/${encodeURIComponent(buildId)}`
1131
+ `${trimTrailingSlashes2(buildServicePath)}/builds/${encodeURIComponent(buildId)}`
1109
1132
  );
1110
1133
  return fromSnakeKeys(raw);
1111
1134
  }
1112
1135
  async cancelBuild(buildServicePath, buildId) {
1113
- await this.http.requestResponse(
1136
+ await this.transport.requestResponse(
1114
1137
  "POST",
1115
- `${trimTrailingSlashes(buildServicePath)}/builds/${encodeURIComponent(buildId)}/cancel`
1138
+ `${trimTrailingSlashes2(buildServicePath)}/builds/${encodeURIComponent(buildId)}/cancel`
1116
1139
  );
1117
1140
  }
1118
1141
  async *streamBuildLogs(buildServicePath, buildId, signal) {
1119
- const stream = await this.http.requestStream(
1142
+ const stream = this.transport.stream(
1120
1143
  "GET",
1121
- `${trimTrailingSlashes(buildServicePath)}/builds/${encodeURIComponent(buildId)}/logs`,
1122
- { signal }
1144
+ `${trimTrailingSlashes2(buildServicePath)}/builds/${encodeURIComponent(buildId)}/logs`,
1145
+ signal
1123
1146
  );
1124
- for await (const event of parseSSEStream(stream, signal)) {
1147
+ for await (const event of stream) {
1125
1148
  yield fromSnakeKeys(event);
1126
1149
  }
1127
1150
  }
@@ -1134,7 +1157,7 @@ var init_cloud_client = __esm({
1134
1157
  input.name
1135
1158
  );
1136
1159
  }
1137
- return this.http.requestResponse("POST", path3, {
1160
+ return this.transport.requestResponse("POST", path3, {
1138
1161
  body: form,
1139
1162
  headers: { Accept: "application/json" }
1140
1163
  });
@@ -1143,10 +1166,10 @@ var init_cloud_client = __esm({
1143
1166
  return `/v1/namespaces/${encodeURIComponent(this.namespace)}/${subpath.replace(/^\/+/, "")}`;
1144
1167
  }
1145
1168
  async existingApplicationPublicEndpointId(applicationName) {
1146
- const response = await this.http.requestResponse(
1169
+ const response = await this.transport.requestResponse(
1147
1170
  "GET",
1148
1171
  this.namespacePath(`applications/${encodeURIComponent(applicationName)}`),
1149
- { allowedErrorStatusCodes: /* @__PURE__ */ new Set([404]) }
1172
+ { statusOnlyCodes: /* @__PURE__ */ new Set([404]) }
1150
1173
  );
1151
1174
  if (response.status === 404) {
1152
1175
  return void 0;
@@ -1289,7 +1312,7 @@ function nativePackageName(platform = process.platform, arch = process.arch, opt
1289
1312
  function loadNative() {
1290
1313
  const target = nativeTargetId();
1291
1314
  const bindingPath = nativeBindingPath();
1292
- const require2 = (0, import_node_module.createRequire)(importMetaUrl);
1315
+ const require2 = (0, import_node_module2.createRequire)(importMetaUrl);
1293
1316
  if (fs.existsSync(bindingPath)) return require2(bindingPath);
1294
1317
  const packageName = nativePackageName();
1295
1318
  if (!packageName) {
@@ -1308,14 +1331,14 @@ function loadNative() {
1308
1331
  }
1309
1332
  return require2(packageEntry);
1310
1333
  }
1311
- var import_libc, fs, import_node_module, import_node_path, import_node_url, NATIVE_PACKAGES, cachedLinuxLibc;
1334
+ var import_libc, fs, import_node_module2, import_node_path, import_node_url, NATIVE_PACKAGES, cachedLinuxLibc;
1312
1335
  var init_native_binding = __esm({
1313
1336
  "src/native-binding.ts"() {
1314
1337
  "use strict";
1315
1338
  init_cjs_shims();
1316
1339
  import_libc = __toESM(require_libc(), 1);
1317
1340
  fs = __toESM(require("fs"), 1);
1318
- import_node_module = require("module");
1341
+ import_node_module2 = require("module");
1319
1342
  import_node_path = __toESM(require("path"), 1);
1320
1343
  import_node_url = require("url");
1321
1344
  NATIVE_PACKAGES = {
@@ -3867,249 +3890,10 @@ var MountCli = class {
3867
3890
 
3868
3891
  // src/filesystem.ts
3869
3892
  init_defaults();
3870
-
3871
- // src/native-sandbox.ts
3872
- init_cjs_shims();
3873
- init_errors();
3874
-
3875
- // src/native-worker-client.ts
3876
- init_cjs_shims();
3877
- var import_node_module2 = require("module");
3878
- var import_node_worker_threads = require("worker_threads");
3879
-
3880
- // src/native-worker-protocol.ts
3881
- init_cjs_shims();
3882
- var cancelNativeCall = /* @__PURE__ */ Symbol.for("tensorlake.native.cancel.v1");
3883
- var closeNativeHandle = /* @__PURE__ */ Symbol.for("tensorlake.native.close.v1");
3884
-
3885
- // src/url.ts
3886
- init_cjs_shims();
3887
- init_defaults();
3888
- function trimTrailingSlashes2(url) {
3889
- return url.endsWith("/") ? url.slice(0, -1) : url;
3890
- }
3891
- function resolveProxyTarget(proxyUrl, sandboxId) {
3892
- try {
3893
- const parsed = new URL(proxyUrl);
3894
- const host = parsed.hostname;
3895
- if (host === "localhost" || host === "127.0.0.1") {
3896
- return {
3897
- baseUrl: trimTrailingSlashes2(proxyUrl),
3898
- hostHeader: `${sandboxId}.local`,
3899
- sandboxIdHeader: void 0
3900
- };
3901
- }
3902
- const port = parsed.port ? `:${parsed.port}` : "";
3903
- return {
3904
- baseUrl: `${parsed.protocol}//${host}${port}`,
3905
- hostHeader: void 0,
3906
- sandboxIdHeader: sandboxId
3907
- };
3908
- } catch {
3909
- return {
3910
- baseUrl: `${trimTrailingSlashes2(proxyUrl)}/${sandboxId}`,
3911
- hostHeader: void 0,
3912
- sandboxIdHeader: void 0
3913
- };
3914
- }
3915
- }
3916
-
3917
- // src/native-worker-client.ts
3918
- var NativeWorkerClient = class {
3919
- constructor(workerPath = () => (0, import_node_module2.createRequire)(importMetaUrl).resolve(
3920
- "tensorlake/internal/native-worker"
3921
- )) {
3922
- this.workerPath = workerPath;
3923
- }
3924
- worker;
3925
- nextId = 1;
3926
- registered = /* @__PURE__ */ new Set();
3927
- pending = /* @__PURE__ */ new Map();
3928
- finalizers = new FinalizationRegistry(
3929
- (id) => this.release(id)
3930
- );
3931
- handle(kind, args, parent) {
3932
- const handle = { id: this.nextId++, kind, args, parent };
3933
- this.finalizers.register(handle, handle.id);
3934
- let closed = false;
3935
- return new Proxy(
3936
- {},
3937
- {
3938
- get: (_target, method) => {
3939
- if (method === "then") return void 0;
3940
- if (method === closeNativeHandle)
3941
- return () => {
3942
- closed = true;
3943
- this.release(handle.id);
3944
- };
3945
- if (method === "connectProxy")
3946
- return (...proxyArgs) => {
3947
- if (closed) throw new Error("Tensorlake native client is closed");
3948
- return this.handle("NativeSandboxProxyClient", proxyArgs, handle);
3949
- };
3950
- if (method === "baseUrl")
3951
- return () => resolveProxyTarget(String(args[0]), String(args[1])).baseUrl;
3952
- if (typeof method !== "string") return void 0;
3953
- return (...callArgs) => {
3954
- if (closed)
3955
- return Promise.reject(
3956
- new Error("Tensorlake native client is closed")
3957
- );
3958
- const emit = typeof callArgs.at(-1) === "function" ? callArgs.pop() : void 0;
3959
- return this.call(handle, method, callArgs, emit);
3960
- };
3961
- }
3962
- }
3963
- );
3964
- }
3965
- call(handle, method, args, emit) {
3966
- const id = this.nextId++;
3967
- let worker;
3968
- const promise = new Promise((resolve, reject) => {
3969
- try {
3970
- worker = this.getWorker();
3971
- this.pending.set(id, { resolve, reject, emit, handle });
3972
- worker.ref();
3973
- if (handle) this.register(handle, worker);
3974
- this.send(worker, {
3975
- type: "call",
3976
- id,
3977
- handleId: handle?.id,
3978
- method,
3979
- args,
3980
- stream: !!emit
3981
- });
3982
- } catch (error) {
3983
- this.pending.delete(id);
3984
- this.unrefIfIdle();
3985
- reject(error);
3986
- }
3987
- });
3988
- promise[cancelNativeCall] = () => {
3989
- const pending = this.pending.get(id);
3990
- if (pending && worker) {
3991
- pending.emit = void 0;
3992
- this.send(worker, { type: "cancel", id });
3993
- }
3994
- };
3995
- return promise;
3996
- }
3997
- getWorker() {
3998
- if (this.worker) return this.worker;
3999
- const worker = new import_node_worker_threads.Worker(this.workerPath(), {
4000
- env: import_node_worker_threads.SHARE_ENV,
4001
- name: "tensorlake-native"
4002
- });
4003
- this.worker = worker;
4004
- worker.on("message", (message) => {
4005
- const pending = this.pending.get(message.id);
4006
- if (!pending || this.worker !== worker) return;
4007
- if (message.type === "event") {
4008
- Promise.resolve().then(() => pending.emit?.(message.value)).then(
4009
- () => {
4010
- if (this.worker === worker)
4011
- this.send(worker, { type: "ack", id: message.id });
4012
- },
4013
- (error) => {
4014
- this.send(worker, { type: "cancel", id: message.id });
4015
- pending.reject(error);
4016
- }
4017
- );
4018
- return;
4019
- }
4020
- this.pending.delete(message.id);
4021
- if (message.type === "error") {
4022
- const error = new Error(message.error.message);
4023
- error.name = message.error.name;
4024
- error.stack = message.error.stack ?? error.stack;
4025
- pending.reject(error);
4026
- } else {
4027
- pending.resolve(message.value);
4028
- }
4029
- this.unrefIfIdle();
4030
- });
4031
- const fail = (error) => {
4032
- if (this.worker !== worker) return;
4033
- this.worker = void 0;
4034
- this.registered.clear();
4035
- for (const pending of this.pending.values()) pending.reject(error);
4036
- this.pending.clear();
4037
- void worker.terminate();
4038
- };
4039
- worker.on("error", fail);
4040
- worker.on("messageerror", fail);
4041
- worker.on(
4042
- "exit",
4043
- (code) => fail(
4044
- new Error(
4045
- `Tensorlake native worker exited (${code}); in-flight operations were not retried`
4046
- )
4047
- )
4048
- );
4049
- worker.unref();
4050
- return worker;
4051
- }
4052
- register(handle, worker) {
4053
- if (this.registered.has(handle.id)) return;
4054
- if (handle.parent) this.register(handle.parent, worker);
4055
- this.send(worker, {
4056
- type: "create",
4057
- handle: { id: handle.id, kind: handle.kind, args: handle.args },
4058
- parentId: handle.parent?.id
4059
- });
4060
- this.registered.add(handle.id);
4061
- }
4062
- release(handleId) {
4063
- if (this.worker && this.registered.delete(handleId))
4064
- this.send(this.worker, { type: "release", handleId });
4065
- }
4066
- send(worker, message) {
4067
- worker.postMessage(message);
4068
- }
4069
- unrefIfIdle() {
4070
- if (this.pending.size === 0) this.worker?.unref();
4071
- }
4072
- };
4073
- function createWorkerBinding(runtime) {
4074
- return {
4075
- NativeSandboxClient: class {
4076
- constructor(...args) {
4077
- return runtime.handle("NativeSandboxClient", args);
4078
- }
4079
- },
4080
- NativeSandboxProxyClient: class {
4081
- constructor(...args) {
4082
- return runtime.handle("NativeSandboxProxyClient", args);
4083
- }
4084
- },
4085
- NativeRepositoryClient: class {
4086
- constructor(...args) {
4087
- return runtime.handle("NativeRepositoryClient", args);
4088
- }
4089
- },
4090
- validateManagedName: (name) => runtime.call(void 0, "validateManagedName", [name])
4091
- };
4092
- }
4093
- var runtimeKey = /* @__PURE__ */ Symbol.for(
4094
- `tensorlake.native.worker.${false ? "source" : "0.5.131"}.v1`
4095
- );
4096
- var runtimes = globalThis;
4097
- function workerBinding() {
4098
- return createWorkerBinding(
4099
- runtimes[runtimeKey] ??= new NativeWorkerClient()
4100
- );
4101
- }
4102
-
4103
- // src/native-sandbox.ts
4104
- var cachedBinding;
4105
- function loadNativeSandboxBinding() {
4106
- return cachedBinding ??= workerBinding();
4107
- }
4108
-
4109
- // src/filesystem.ts
3893
+ init_native_sandbox();
4110
3894
  init_sandbox_image();
4111
3895
  var FILESYSTEM_REPO_KIND = "filesystem";
4112
- function translateNativeError(error, notFound) {
3896
+ function translateNativeError2(error, notFound) {
4113
3897
  const message = error instanceof Error ? error.message : String(error);
4114
3898
  let payload;
4115
3899
  try {
@@ -4132,11 +3916,11 @@ function translateNativeError(error, notFound) {
4132
3916
  }
4133
3917
  return new FilesystemError(detail);
4134
3918
  }
4135
- async function callNative(fn, notFound) {
3919
+ async function callNative2(fn, notFound) {
4136
3920
  try {
4137
3921
  return await fn();
4138
3922
  } catch (error) {
4139
- throw translateNativeError(error, notFound);
3923
+ throw translateNativeError2(error, notFound);
4140
3924
  }
4141
3925
  }
4142
3926
  var FsCli = class extends MountCli {
@@ -4238,7 +4022,7 @@ var FilesystemClient = class {
4238
4022
  if (name.length === 0) {
4239
4023
  throw new FilesystemError("filesystem name must not be empty");
4240
4024
  }
4241
- const raw = await callNative(() => this.native.createFilesystem(name));
4025
+ const raw = await callNative2(() => this.native.createFilesystem(name));
4242
4026
  const created = JSON.parse(raw);
4243
4027
  return new Filesystem(
4244
4028
  this,
@@ -4258,7 +4042,7 @@ var FilesystemClient = class {
4258
4042
  "fork and base filesystem names must not be empty"
4259
4043
  );
4260
4044
  }
4261
- await callNative(
4045
+ await callNative2(
4262
4046
  () => this.native.forkFilesystem(
4263
4047
  name,
4264
4048
  baseFilesystem,
@@ -4270,7 +4054,7 @@ var FilesystemClient = class {
4270
4054
  }
4271
4055
  /** Return a handle to an existing filesystem (verifies it exists). */
4272
4056
  async get(name) {
4273
- const traced = await callNative(
4057
+ const traced = await callNative2(
4274
4058
  () => this.native.filesystemMeta(name),
4275
4059
  new FilesystemNotFoundError(name)
4276
4060
  );
@@ -4288,7 +4072,7 @@ var FilesystemClient = class {
4288
4072
  }
4289
4073
  /** List all filesystems in the project. */
4290
4074
  async list() {
4291
- const traced = await callNative(() => this.native.listFilesystems());
4075
+ const traced = await callNative2(() => this.native.listFilesystems());
4292
4076
  const page = JSON.parse(traced.json);
4293
4077
  return (page.repos ?? []).map((repo) => ({
4294
4078
  name: String(repo.name ?? ""),
@@ -4299,7 +4083,7 @@ var FilesystemClient = class {
4299
4083
  }
4300
4084
  /** Permanently delete a filesystem and all its snapshots. */
4301
4085
  async delete(name) {
4302
- await callNative(
4086
+ await callNative2(
4303
4087
  () => this.native.deleteFilesystem(name),
4304
4088
  new FilesystemNotFoundError(name)
4305
4089
  );
@@ -4353,7 +4137,7 @@ var Filesystem = class {
4353
4137
  */
4354
4138
  async branch() {
4355
4139
  if (!this.defaultBranch) {
4356
- const traced = await callNative(
4140
+ const traced = await callNative2(
4357
4141
  () => this.native.filesystemMeta(this.name),
4358
4142
  new FilesystemNotFoundError(this.name)
4359
4143
  );
@@ -4408,7 +4192,7 @@ var Filesystem = class {
4408
4192
  const writes = entries.map(([path3, localPath]) => ({ path: path3, localPath }));
4409
4193
  const resolvedMessage = message || `write ${writes.length} local file(s) via SDK`;
4410
4194
  const branch = await this.branch();
4411
- const traced = await callNative(
4195
+ const traced = await callNative2(
4412
4196
  () => this.native.pushFilesystemPaths(
4413
4197
  this.name,
4414
4198
  writes,
@@ -4456,7 +4240,7 @@ var Filesystem = class {
4456
4240
  }
4457
4241
  async publishChanges(writes, deletes, moves, copies, message) {
4458
4242
  const branch = await this.branch();
4459
- const traced = await callNative(
4243
+ const traced = await callNative2(
4460
4244
  () => this.native.pushFilesystemFiles(
4461
4245
  this.name,
4462
4246
  writes,
@@ -4498,7 +4282,7 @@ var Filesystem = class {
4498
4282
  */
4499
4283
  async snapshot(message = "snapshot via SDK") {
4500
4284
  const resolvedMessage = message || "snapshot via SDK";
4501
- const traced = await callNative(
4285
+ const traced = await callNative2(
4502
4286
  () => this.native.retainFilesystemSnapshot(
4503
4287
  this.name,
4504
4288
  resolvedMessage,
@@ -4514,7 +4298,7 @@ var Filesystem = class {
4514
4298
  }
4515
4299
  /** List explicitly retained snapshots without reading filesystem contents. */
4516
4300
  async listSnapshots() {
4517
- const traced = await callNative(
4301
+ const traced = await callNative2(
4518
4302
  () => this.native.listFilesystemSnapshots(this.name),
4519
4303
  new FilesystemNotFoundError(this.name)
4520
4304
  );
@@ -4527,7 +4311,7 @@ var Filesystem = class {
4527
4311
  }
4528
4312
  /** Delete one permanent retention point; shared/head-reachable bytes remain. */
4529
4313
  async deleteSnapshot(snapshot) {
4530
- await callNative(
4314
+ await callNative2(
4531
4315
  () => this.native.deleteFilesystemSnapshot(this.name, snapshot),
4532
4316
  new FilesystemNotFoundError(this.name)
4533
4317
  );
@@ -4555,7 +4339,7 @@ var Filesystem = class {
4555
4339
  );
4556
4340
  }
4557
4341
  const resolvedVersion = options.version || await this.branch();
4558
- const traced = await callNative(
4342
+ const traced = await callNative2(
4559
4343
  () => this.native.readFilesystemFile(
4560
4344
  this.name,
4561
4345
  path3,
@@ -4586,7 +4370,7 @@ var Filesystem = class {
4586
4370
  /** List one directory (non-recursive) at `version`. */
4587
4371
  async listFiles(dirPath = "", version) {
4588
4372
  const resolvedVersion = version || await this.branch();
4589
- const traced = await callNative(
4373
+ const traced = await callNative2(
4590
4374
  () => this.native.listFilesystemTree(this.name, dirPath, resolvedVersion),
4591
4375
  new FileNotFoundInFilesystemError(this.name, dirPath || "/")
4592
4376
  );
@@ -4596,7 +4380,7 @@ var Filesystem = class {
4596
4380
  // -- status -------------------------------------------------------------------
4597
4381
  /** Remote status: identity plus the current native version. */
4598
4382
  async status() {
4599
- const metaTraced = await callNative(
4383
+ const metaTraced = await callNative2(
4600
4384
  () => this.native.filesystemMeta(this.name),
4601
4385
  new FilesystemNotFoundError(this.name)
4602
4386
  );
@@ -4606,7 +4390,7 @@ var Filesystem = class {
4606
4390
  let versionId = null;
4607
4391
  let generation = null;
4608
4392
  try {
4609
- const refTraced = await callNative(
4393
+ const refTraced = await callNative2(
4610
4394
  () => this.native.filesystemRefStatus(this.name, defaultBranch)
4611
4395
  );
4612
4396
  const ref = JSON.parse(refTraced.json);