@enclave-run/sdk 0.0.0-dev.5 → 0.1.0

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.
package/dist/index.mjs CHANGED
@@ -60,7 +60,7 @@ import createClient from "openapi-fetch";
60
60
  import platform2 from "platform";
61
61
 
62
62
  // package.json
63
- var version = "0.0.0-dev.5";
63
+ var version = "0.1.0";
64
64
 
65
65
  // src/utils.ts
66
66
  import platform from "platform";
@@ -102,12 +102,6 @@ async function sha256(data) {
102
102
  function timeoutToSeconds(timeout) {
103
103
  return Math.ceil(timeout / 1e3);
104
104
  }
105
- async function dynamicImport(module) {
106
- if (runtime === "browser") {
107
- throw new Error("Browser runtime is not supported for dynamic import");
108
- }
109
- return await import(module);
110
- }
111
105
  function ansiRegex({ onlyFirst = false } = {}) {
112
106
  const ST = "(?:\\u0007|\\u001B\\u005C|\\u009C)";
113
107
  const osc = `(?:\\u001B\\][\\s\\S]*?${ST})`;
@@ -172,6 +166,13 @@ var OutcomeUnknownError = class extends SandboxError {
172
166
  this.cause = cause;
173
167
  }
174
168
  };
169
+ var SandboxCreateFailedError = class extends SandboxError {
170
+ constructor(message, recovery) {
171
+ super(message);
172
+ this.name = "SandboxCreateFailedError";
173
+ this.recovery = recovery;
174
+ }
175
+ };
175
176
  var SandboxCreateRejectedError = class extends SandboxError {
176
177
  constructor(message, recovery, reason, spilloverAllowed = false, capacityTier = "shared") {
177
178
  super(message);
@@ -286,11 +287,11 @@ function formatLog(log) {
286
287
  return JSON.parse(JSON.stringify(log));
287
288
  }
288
289
  function createRpcLogger(logger) {
289
- function logEach(stream) {
290
+ function logEach(stream2) {
290
291
  return __asyncGenerator(this, null, function* () {
291
292
  var _a3;
292
293
  try {
293
- for (var iter = __forAwait(stream), more, temp, error; more = !(temp = yield new __await(iter.next())).done; more = false) {
294
+ for (var iter = __forAwait(stream2), more, temp, error; more = !(temp = yield new __await(iter.next())).done; more = false) {
294
295
  const m = temp.value;
295
296
  (_a3 = logger.debug) == null ? void 0 : _a3.call(logger, "Response stream:", formatLog(m));
296
297
  yield m;
@@ -3529,8 +3530,9 @@ var SandboxApi = class {
3529
3530
  return operation.sandbox;
3530
3531
  }
3531
3532
  if (operation.state === "failed") {
3532
- throw new SandboxError(
3533
- (_b = (_a3 = operation.error) == null ? void 0 : _a3.message) != null ? _b : "Sandbox create failed after admission"
3533
+ throw new SandboxCreateFailedError(
3534
+ (_b = (_a3 = operation.error) == null ? void 0 : _a3.message) != null ? _b : "Sandbox create failed after admission",
3535
+ recovery
3534
3536
  );
3535
3537
  }
3536
3538
  await new Promise((resolve) => setTimeout(resolve, 25));
@@ -4424,6 +4426,10 @@ var SandboxRegionScope = class {
4424
4426
  }
4425
4427
  };
4426
4428
 
4429
+ // src/template/buildApi.ts
4430
+ import fs2 from "fs";
4431
+ import stream from "stream";
4432
+
4427
4433
  // src/template/logger.ts
4428
4434
  import chalk from "chalk";
4429
4435
  var LogEntry = class {
@@ -4545,16 +4551,30 @@ function defaultBuildLogger(options) {
4545
4551
  // src/template/utils.ts
4546
4552
  import crypto2 from "crypto";
4547
4553
  import fs from "fs";
4554
+ import os from "os";
4548
4555
  import path from "path";
4549
4556
  import url from "url";
4550
4557
 
4551
4558
  // src/template/consts.ts
4552
4559
  var FINALIZE_STEP_NAME = "finalize";
4560
+ var FILE_UPLOAD_TIMEOUT_MS = 36e5;
4553
4561
  var BASE_STEP_NAME = "base";
4554
4562
  var STACK_TRACE_DEPTH = 3;
4555
4563
  var RESOLVE_SYMLINKS = false;
4556
4564
 
4557
4565
  // src/template/utils.ts
4566
+ async function loadGlob() {
4567
+ if (runtime === "browser") {
4568
+ throw new Error("Browser runtime is not supported for local file copies");
4569
+ }
4570
+ return await import("glob");
4571
+ }
4572
+ async function loadTar() {
4573
+ if (runtime === "browser") {
4574
+ throw new Error("Browser runtime is not supported for local file copies");
4575
+ }
4576
+ return await import("tar");
4577
+ }
4558
4578
  function validateRelativePath(src, stackTrace) {
4559
4579
  if (path.isAbsolute(src)) {
4560
4580
  const error = new TemplateError(
@@ -4585,7 +4605,7 @@ function normalizePath(path2) {
4585
4605
  return path2.replace(/\\/g, "/");
4586
4606
  }
4587
4607
  async function getAllFilesInPath(src, contextPath, ignorePatterns, includeDirectories = true) {
4588
- const { glob } = await dynamicImport("glob");
4608
+ const { glob } = await loadGlob();
4589
4609
  const files = /* @__PURE__ */ new Map();
4590
4610
  const globFiles = await glob(src, {
4591
4611
  ignore: ignorePatterns,
@@ -4701,32 +4721,48 @@ function getCallerDirectory(depth) {
4701
4721
  function padOctal(mode) {
4702
4722
  return mode.toString(8).padStart(4, "0");
4703
4723
  }
4704
- async function tarFileStream(fileName, fileContextPath, ignorePatterns, resolveSymlinks) {
4705
- const { create } = await dynamicImport("tar");
4724
+ async function getTarArchiveInputs(fileName, fileContextPath, ignorePatterns) {
4725
+ const { create } = await loadTar();
4706
4726
  const allFiles = await getAllFilesInPath(
4707
4727
  fileName,
4708
4728
  fileContextPath,
4709
4729
  ignorePatterns,
4710
4730
  true
4711
4731
  );
4712
- const filePaths = allFiles.map((file) => file.relativePosix());
4713
- return create(
4714
- {
4715
- gzip: true,
4716
- cwd: fileContextPath,
4717
- follow: resolveSymlinks,
4718
- noDirRecurse: true
4719
- },
4720
- filePaths
4721
- );
4732
+ return {
4733
+ create,
4734
+ filePaths: allFiles.map((file) => file.relativePosix())
4735
+ };
4722
4736
  }
4723
- async function tarFileStreamUpload(fileName, fileContextPath, ignorePatterns, resolveSymlinks) {
4724
- return tarFileStream(
4737
+ async function spoolTarArchive(fileName, fileContextPath, ignorePatterns, resolveSymlinks) {
4738
+ const { create, filePaths } = await getTarArchiveInputs(
4725
4739
  fileName,
4726
4740
  fileContextPath,
4727
- ignorePatterns,
4728
- resolveSymlinks
4741
+ ignorePatterns
4729
4742
  );
4743
+ const tmpDir = await fs.promises.mkdtemp(
4744
+ path.join(os.tmpdir(), "enclave-template-")
4745
+ );
4746
+ const tarPath = path.join(tmpDir, "context.tar.gz");
4747
+ const cleanup = () => fs.promises.rm(tmpDir, { recursive: true, force: true }).catch(() => {
4748
+ });
4749
+ try {
4750
+ await create(
4751
+ {
4752
+ gzip: true,
4753
+ cwd: fileContextPath,
4754
+ follow: resolveSymlinks,
4755
+ noDirRecurse: true,
4756
+ file: tarPath
4757
+ },
4758
+ filePaths
4759
+ );
4760
+ const { size } = await fs.promises.stat(tarPath);
4761
+ return { path: tarPath, size, cleanup };
4762
+ } catch (error) {
4763
+ await cleanup();
4764
+ throw error;
4765
+ }
4730
4766
  }
4731
4767
  function getBuildStepIndex(step, stackTracesLength) {
4732
4768
  if (step === BASE_STEP_NAME) {
@@ -4786,22 +4822,34 @@ async function getFileUploadLink(client, { templateID, filesHash }, stackTrace)
4786
4822
  }
4787
4823
  async function uploadFile(options, stackTrace) {
4788
4824
  const { fileName, url: url2, fileContextPath, ignorePatterns, resolveSymlinks } = options;
4825
+ let cleanup;
4826
+ let bodyStream;
4789
4827
  try {
4790
- const uploadStream = await tarFileStreamUpload(
4828
+ const archive = await spoolTarArchive(
4791
4829
  fileName,
4792
4830
  fileContextPath,
4793
4831
  ignorePatterns,
4794
4832
  resolveSymlinks
4795
4833
  );
4834
+ cleanup = archive.cleanup;
4835
+ bodyStream = fs2.createReadStream(archive.path);
4796
4836
  const res = await fetch(url2, {
4797
4837
  method: "PUT",
4798
- // @ts-expect-error
4799
- body: uploadStream,
4838
+ body: stream.Readable.toWeb(bodyStream),
4839
+ headers: {
4840
+ "Content-Length": archive.size.toString()
4841
+ },
4842
+ signal: AbortSignal.timeout(FILE_UPLOAD_TIMEOUT_MS),
4843
+ // Node fetch requires duplex for a streaming request body, but the DOM
4844
+ // RequestInit type does not expose it.
4845
+ // @ts-expect-error Node fetch extension
4800
4846
  duplex: "half"
4801
4847
  });
4802
4848
  if (!res.ok) {
4849
+ const responseDetails = (await res.text().catch(() => "")).slice(0, 4096);
4850
+ const status = `${res.status} ${res.statusText}`.trim();
4803
4851
  throw new FileUploadError(
4804
- `Failed to upload file: ${res.statusText}`,
4852
+ `Failed to upload file: ${status}${responseDetails ? ` - ${responseDetails}` : ""}`,
4805
4853
  stackTrace
4806
4854
  );
4807
4855
  }
@@ -4810,6 +4858,14 @@ async function uploadFile(options, stackTrace) {
4810
4858
  throw error;
4811
4859
  }
4812
4860
  throw new FileUploadError(`Failed to upload file: ${error}`, stackTrace);
4861
+ } finally {
4862
+ if (bodyStream && !bodyStream.closed) {
4863
+ await new Promise((resolve) => {
4864
+ bodyStream == null ? void 0 : bodyStream.once("close", resolve);
4865
+ bodyStream == null ? void 0 : bodyStream.destroy();
4866
+ });
4867
+ }
4868
+ await (cleanup == null ? void 0 : cleanup());
4813
4869
  }
4814
4870
  }
4815
4871
  async function triggerBuild(client, { templateID, buildID, template }) {
@@ -4998,7 +5054,7 @@ async function getTemplateTags(client, { templateID }) {
4998
5054
  import {
4999
5055
  DockerfileParser
5000
5056
  } from "dockerfile-ast";
5001
- import fs2 from "fs";
5057
+ import fs3 from "fs";
5002
5058
 
5003
5059
  // src/template/readycmd.ts
5004
5060
  var ReadyCmd = class {
@@ -5035,8 +5091,8 @@ function waitForTimeout(timeout) {
5035
5091
  function parseDockerfile(dockerfileContentOrPath, templateBuilder) {
5036
5092
  let dockerfileContent;
5037
5093
  try {
5038
- if (fs2.existsSync(dockerfileContentOrPath) && fs2.statSync(dockerfileContentOrPath).isFile()) {
5039
- dockerfileContent = fs2.readFileSync(dockerfileContentOrPath, "utf-8");
5094
+ if (fs3.existsSync(dockerfileContentOrPath) && fs3.statSync(dockerfileContentOrPath).isFile()) {
5095
+ dockerfileContent = fs3.readFileSync(dockerfileContentOrPath, "utf-8");
5040
5096
  } else {
5041
5097
  dockerfileContent = dockerfileContentOrPath;
5042
5098
  }
@@ -6402,6 +6458,7 @@ export {
6402
6458
  ReadyCmd,
6403
6459
  RegionCapacityError,
6404
6460
  Sandbox,
6461
+ SandboxCreateFailedError,
6405
6462
  SandboxCreateRejectedError,
6406
6463
  SandboxError,
6407
6464
  SandboxRegionScope,