@metasession.co/devaudit-cli 0.3.10 → 0.3.11

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.js CHANGED
@@ -3,7 +3,7 @@ import { Command, Option } from 'commander';
3
3
  import { createConsola } from 'consola';
4
4
  import { execa } from 'execa';
5
5
  import { join, resolve, basename, dirname, relative } from 'path';
6
- import { promises } from 'fs';
6
+ import { promises, openAsBlob } from 'fs';
7
7
  import envPaths from 'env-paths';
8
8
  import { fileURLToPath, pathToFileURL } from 'url';
9
9
  import { validateManifest } from '@metasession.co/devaudit-plugin-sdk';
@@ -56,7 +56,7 @@ function emitJsonResult(payload) {
56
56
 
57
57
  // package.json
58
58
  var package_default = {
59
- version: "0.3.10"};
59
+ version: "0.3.11"};
60
60
 
61
61
  // src/lib/version.ts
62
62
  var CLI_VERSION = package_default.version;
@@ -602,6 +602,7 @@ var INITIAL_BACKOFF_MS = 1e3;
602
602
  var DEFAULT_PRESIGNED_THRESHOLD_BYTES = 26214400;
603
603
  var DEFAULT_PRESIGNED_MAX_ATTEMPTS = 3;
604
604
  var DEFAULT_PRESIGNED_UPLOAD_MAX_TIME_SECONDS = 300;
605
+ var STUB_PREFIX_BYTES = 4096;
605
606
  function maxAttempts() {
606
607
  const raw = Number.parseInt(process.env["UPLOAD_MAX_ATTEMPTS"] ?? "", 10);
607
608
  return Number.isFinite(raw) && raw > 0 ? raw : DEFAULT_MAX_ATTEMPTS;
@@ -629,16 +630,63 @@ async function collectFiles(filePath) {
629
630
  throw new Error(`${filePath} is neither a file nor a directory.`);
630
631
  }
631
632
  var STUB_BANNER = /STARTER TEMPLATE.+REPLACE BEFORE/;
632
- function isUneditedStub(buf) {
633
- return STUB_BANNER.test(buf.toString("utf-8"));
634
- }
633
+ var TEXT_STUB_EXTENSIONS = /* @__PURE__ */ new Set([
634
+ ".md",
635
+ ".markdown",
636
+ ".txt",
637
+ ".json",
638
+ ".yml",
639
+ ".yaml",
640
+ ".csv",
641
+ ".html",
642
+ ".xml",
643
+ ".log"
644
+ ]);
635
645
  function delay(ms) {
636
646
  return new Promise((res) => setTimeout(res, ms));
637
647
  }
638
- function buildUploadForm(file, buf, opts) {
648
+ function extensionOf(file) {
649
+ const dot = file.lastIndexOf(".");
650
+ return dot === -1 ? "" : file.slice(dot).toLowerCase();
651
+ }
652
+ function isTextLikeEvidenceFile(file) {
653
+ return TEXT_STUB_EXTENSIONS.has(extensionOf(file));
654
+ }
655
+ async function readFilePrefix(file, bytes) {
656
+ const handle = await promises.open(file, "r");
657
+ try {
658
+ const buf = Buffer.alloc(bytes);
659
+ const { bytesRead } = await handle.read(buf, 0, bytes, 0);
660
+ return buf.subarray(0, bytesRead).toString("utf-8");
661
+ } finally {
662
+ await handle.close();
663
+ }
664
+ }
665
+ async function isUneditedStub(file) {
666
+ if (!isTextLikeEvidenceFile(file)) return false;
667
+ const prefix = await readFilePrefix(file, STUB_PREFIX_BYTES);
668
+ return STUB_BANNER.test(prefix);
669
+ }
670
+ async function createUploadSource(file) {
671
+ const mimeType = deriveMimeType(file);
672
+ const { size } = await promises.stat(file);
673
+ try {
674
+ return {
675
+ blob: await openAsBlob(file, { type: mimeType }),
676
+ size,
677
+ mimeType
678
+ };
679
+ } catch {
680
+ return {
681
+ blob: new Blob([await promises.readFile(file)], { type: mimeType }),
682
+ size,
683
+ mimeType
684
+ };
685
+ }
686
+ }
687
+ function buildUploadForm(file, source, opts) {
639
688
  const form = new FormData();
640
- const blob = new Blob([new Uint8Array(buf)]);
641
- form.set("file", blob, basename(file));
689
+ form.set("file", source.blob, basename(file));
642
690
  form.set("projectSlug", opts.projectSlug);
643
691
  form.set("requirementId", opts.requirementId);
644
692
  form.set("evidenceType", opts.evidenceType);
@@ -684,7 +732,7 @@ async function probeBaseUrlDrift(baseUrl) {
684
732
  return null;
685
733
  }
686
734
  }
687
- async function uploadOne(file, buf, opts) {
735
+ async function uploadOne(file, source, opts) {
688
736
  const attempts = maxAttempts();
689
737
  const timeoutSeconds = uploadMaxTimeSeconds();
690
738
  const url = `${opts.baseUrl.replace(/\/$/, "")}/api/evidence/upload`;
@@ -698,7 +746,7 @@ async function uploadOne(file, buf, opts) {
698
746
  res = await fetch(url, {
699
747
  method: "POST",
700
748
  headers: { authorization: `Bearer ${opts.apiKey}` },
701
- body: buildUploadForm(file, buf, opts),
749
+ body: buildUploadForm(file, source, opts),
702
750
  signal: controller.signal
703
751
  });
704
752
  } catch (err) {
@@ -731,14 +779,13 @@ async function uploadOne(file, buf, opts) {
731
779
  return { file, ok: false, status: 0, error: "max retries exhausted" };
732
780
  }
733
781
  var PRESIGNED_FALLBACK = /* @__PURE__ */ Symbol("presigned-fallback");
734
- async function uploadPresigned(file, buf, opts) {
782
+ async function uploadPresigned(file, source, opts) {
735
783
  const baseUrl = opts.baseUrl.replace(/\/$/, "");
736
784
  const presignUrl = `${baseUrl}/api/evidence/upload-url`;
737
785
  const completeUrl = `${baseUrl}/api/evidence/upload-complete`;
738
786
  const maxAttemptsPresigned = DEFAULT_PRESIGNED_MAX_ATTEMPTS;
739
787
  const timeoutSeconds = uploadMaxTimeSeconds();
740
788
  const presignedTimeoutSeconds = DEFAULT_PRESIGNED_UPLOAD_MAX_TIME_SECONDS;
741
- const mimeType = deriveMimeType(file);
742
789
  const metadata = opts.metadata ?? {};
743
790
  let uploadUrl = "";
744
791
  let evidenceId = "";
@@ -760,8 +807,8 @@ async function uploadPresigned(file, buf, opts) {
760
807
  requirementId: opts.requirementId,
761
808
  evidenceType: opts.evidenceType,
762
809
  fileName: basename(file),
763
- fileSizeBytes: buf.byteLength,
764
- mimeType,
810
+ fileSizeBytes: source.size,
811
+ mimeType: source.mimeType,
765
812
  metadata,
766
813
  ...opts.releaseVersion ? { releaseVersion: opts.releaseVersion } : {},
767
814
  ...opts.createReleaseIfMissing ? { createReleaseIfMissing: true } : {},
@@ -816,8 +863,8 @@ async function uploadPresigned(file, buf, opts) {
816
863
  try {
817
864
  res = await fetch(uploadUrl, {
818
865
  method: "PUT",
819
- headers: { "content-type": mimeType },
820
- body: new Uint8Array(buf),
866
+ headers: { "content-type": source.mimeType },
867
+ body: source.blob,
821
868
  signal: controller.signal
822
869
  });
823
870
  } catch (err) {
@@ -898,19 +945,19 @@ async function uploadEvidence(opts) {
898
945
  }
899
946
  const results = [];
900
947
  for (const file of files) {
901
- const buf = await promises.readFile(file);
902
- if (isUneditedStub(buf)) {
948
+ if (await isUneditedStub(file)) {
903
949
  results.push({ file, ok: true, status: 0, skipped: true });
904
950
  continue;
905
951
  }
906
- if (buf.byteLength >= DEFAULT_PRESIGNED_THRESHOLD_BYTES) {
907
- const presignedResult = await uploadPresigned(file, buf, opts);
952
+ const source = await createUploadSource(file);
953
+ if (source.size >= DEFAULT_PRESIGNED_THRESHOLD_BYTES) {
954
+ const presignedResult = await uploadPresigned(file, source, opts);
908
955
  if (presignedResult !== PRESIGNED_FALLBACK) {
909
956
  results.push(presignedResult);
910
957
  continue;
911
958
  }
912
959
  }
913
- results.push(await uploadOne(file, buf, opts));
960
+ results.push(await uploadOne(file, source, opts));
914
961
  }
915
962
  return results;
916
963
  }