@infersec/conduit 1.6.0 → 1.6.2

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/cli.js CHANGED
@@ -6,7 +6,7 @@ const __dirname = __pathDirname(__filename);
6
6
 
7
7
  import { parseArgs } from 'node:util';
8
8
  import 'node:crypto';
9
- import { a as asError, s as startInferenceAgent } from './start-XRPU7RSB.js';
9
+ import { a as asError, s as startInferenceAgent } from './start-CQayYNYZ.js';
10
10
  import 'argon2';
11
11
  import 'node:child_process';
12
12
  import 'node:stream';
@@ -45,8 +45,8 @@ import 'querystring';
45
45
  import 'url';
46
46
  import 'http';
47
47
  import 'crypto';
48
- import 'node:stream/promises';
49
48
  import 'node:fs';
49
+ import 'node:stream/promises';
50
50
  import 'fs/promises';
51
51
  import 'stream/promises';
52
52
  import 'node:string_decoder';
package/dist/index.js CHANGED
@@ -5,7 +5,7 @@ const __filename = __fileURLToPath(import.meta.url);
5
5
  const __dirname = __pathDirname(__filename);
6
6
 
7
7
  import 'node:crypto';
8
- import { s as startInferenceAgent, a as asError } from './start-XRPU7RSB.js';
8
+ import { s as startInferenceAgent, a as asError } from './start-CQayYNYZ.js';
9
9
  import 'argon2';
10
10
  import 'node:child_process';
11
11
  import 'node:stream';
@@ -45,8 +45,8 @@ import 'querystring';
45
45
  import 'url';
46
46
  import 'http';
47
47
  import 'crypto';
48
- import 'node:stream/promises';
49
48
  import 'node:fs';
49
+ import 'node:stream/promises';
50
50
  import 'fs/promises';
51
51
  import 'stream/promises';
52
52
  import 'node:string_decoder';
@@ -30,8 +30,8 @@ import require$$1$3 from 'node:worker_threads';
30
30
  import require$$1$5, { fileURLToPath } from 'node:url';
31
31
  import require$$1$6 from 'node:async_hooks';
32
32
  import require$$1$7 from 'node:console';
33
- import require$$0$b, { mkdir, readFile, writeFile, realpath, readlink, readdir, lstat } from 'node:fs/promises';
34
- import path$1, { dirname, join, win32, posix } from 'node:path';
33
+ import require$$0$b, { mkdir, readFile, writeFile, stat, unlink, rename, realpath, readlink, readdir, lstat } from 'node:fs/promises';
34
+ import path$1, { join, dirname, win32, posix } from 'node:path';
35
35
  import require$$1$8 from 'node:dns';
36
36
  import require$$2$4 from 'node:sqlite';
37
37
  import require$$0$c from 'path';
@@ -44,9 +44,9 @@ import require$$8$1 from 'querystring';
44
44
  import require$$0$f from 'url';
45
45
  import require$$0$g from 'http';
46
46
  import require$$0$h from 'crypto';
47
- import { pipeline, finished } from 'node:stream/promises';
48
47
  import * as actualFS from 'node:fs';
49
48
  import { existsSync, createWriteStream, statSync, readFileSync, appendFileSync, writeFileSync, createReadStream } from 'node:fs';
49
+ import { pipeline, finished } from 'node:stream/promises';
50
50
  import 'fs/promises';
51
51
  import 'stream/promises';
52
52
  import { StringDecoder } from 'node:string_decoder';
@@ -96473,11 +96473,13 @@ const ModelDownloadProgressSchema = object({
96473
96473
  completedFiles: array(string$1().min(1))
96474
96474
  });
96475
96475
 
96476
- const DOWNLOAD_PROGRESS_TIMEOUT = 30000;
96477
- const DOWNLOAD_RETRY_ATTEMPTS = 3;
96476
+ const DOWNLOAD_PROGRESS_TIMEOUT = 60000;
96477
+ const DOWNLOAD_RETRY_ATTEMPTS_FULL = 3;
96478
+ const DOWNLOAD_RETRY_ATTEMPTS_RANGE = 10;
96478
96479
  async function downloadModelViaHuggingFace({ format, huggingFaceToken, modelSlug: rawModelSlug, progressFilePath, targetDirectory }) {
96479
96480
  // Sanitise model ID
96480
- const [modelSlug, variant = null] = rawModelSlug.split(":");
96481
+ const [modelSlugWithRevision, variant = null] = rawModelSlug.split(":");
96482
+ const { modelSlug, revision } = parseModelRevision(modelSlugWithRevision);
96481
96483
  // Prepare directory
96482
96484
  await mkdir(targetDirectory, { recursive: true });
96483
96485
  let progress;
@@ -96512,65 +96514,411 @@ async function downloadModelViaHuggingFace({ format, huggingFaceToken, modelSlug
96512
96514
  console.log("Skipping due to already having completed file:", file.path, file.size);
96513
96515
  continue;
96514
96516
  }
96515
- let downloaded = false;
96516
- let lastError = null;
96517
- for (let attempt = 1; attempt <= DOWNLOAD_RETRY_ATTEMPTS; attempt++) {
96517
+ const rangeInfo = await getRangeInfo({
96518
+ accessToken,
96519
+ filePath: file.path,
96520
+ fileSize: file.size,
96521
+ modelSlug,
96522
+ revision
96523
+ });
96524
+ const { partialPath } = getDownloadPaths({ filePath: file.path, targetDirectory });
96525
+ const shouldAttemptRange = rangeInfo.supportsRanges || existsSync(partialPath);
96526
+ if (shouldAttemptRange) {
96518
96527
  try {
96519
- console.log("Downloading:", file.path, file.size, `(attempt ${attempt})`);
96520
- await mkdir(dirname(join(targetDirectory, file.path)), { recursive: true });
96521
- const response = await downloadFile({
96528
+ await downloadFileWithRange({
96522
96529
  accessToken,
96523
- repo: modelSlug,
96524
- path: file.path
96525
- // path: join(targetDirectory, file.path)
96530
+ filePath: file.path,
96531
+ fileSize: rangeInfo.totalSize ?? file.size,
96532
+ modelSlug,
96533
+ revision,
96534
+ targetDirectory
96526
96535
  });
96527
- if (!response) {
96528
- throw new Error(`Requested file did not return a valid response: ${file.path}`);
96529
- }
96530
- const input = Readable.fromWeb(response.stream());
96531
- const meter = watchStreamProgress(25 * 1024 * 1024); // 25 MiB intervals
96532
- const output = createWriteStream(join(targetDirectory, file.path));
96533
- let progressTimeout = null;
96534
- let lastPercentage = "0.0";
96535
- let lastProgressBytes = 0;
96536
- meter.progress.on("progress", (totalBytes) => {
96537
- lastProgressBytes = totalBytes;
96538
- const percentComplete = ((totalBytes / file.size) * 100).toFixed(1);
96539
- if (lastPercentage !== percentComplete) {
96540
- console.log(` => ${percentComplete}% (${totalBytes} / ${file.size})`);
96541
- }
96542
- lastPercentage = percentComplete;
96543
- clearTimeout(progressTimeout);
96544
- progressTimeout = setTimeout(() => {
96545
- input.destroy(new Error(`Timed out with no progress for ${DOWNLOAD_PROGRESS_TIMEOUT}ms while downloading ${file.path}. Last progress: ${lastPercentage}% (${lastProgressBytes} / ${file.size})`));
96546
- }, DOWNLOAD_PROGRESS_TIMEOUT);
96547
- });
96548
- try {
96549
- await pipeline(input, meter, output);
96550
- }
96551
- finally {
96552
- clearTimeout(progressTimeout);
96553
- }
96554
- downloaded = true;
96555
- break;
96556
96536
  }
96557
96537
  catch (error) {
96558
- lastError = asError(error);
96559
- if (attempt < DOWNLOAD_RETRY_ATTEMPTS) {
96560
- console.warn(`Retrying download (${attempt}/${DOWNLOAD_RETRY_ATTEMPTS}) for ${file.path} due to error: ${lastError.message}`);
96561
- continue;
96538
+ if (error instanceof RangeNotSupportedError) {
96539
+ console.warn(`Range download unavailable for ${file.path}: ${error.message}`);
96540
+ await downloadFileFull({
96541
+ accessToken,
96542
+ filePath: file.path,
96543
+ fileSize: file.size,
96544
+ modelSlug,
96545
+ targetDirectory
96546
+ });
96547
+ }
96548
+ else {
96549
+ throw error;
96562
96550
  }
96563
96551
  }
96564
96552
  }
96565
- if (!downloaded) {
96566
- const errorMessage = `Failed downloading ${file.path} (${file.size} bytes) after ${DOWNLOAD_RETRY_ATTEMPTS} attempts. Last error: ${lastError?.message ?? "Unknown error"}`;
96567
- throw new Error(errorMessage);
96553
+ else {
96554
+ if (rangeInfo.reason) {
96555
+ console.warn(`Range download unavailable for ${file.path}: ${rangeInfo.reason}`);
96556
+ }
96557
+ await downloadFileFull({
96558
+ accessToken,
96559
+ filePath: file.path,
96560
+ fileSize: file.size,
96561
+ modelSlug,
96562
+ targetDirectory
96563
+ });
96568
96564
  }
96569
96565
  // Update progress
96570
96566
  progress.completedFiles.push(file.path);
96571
96567
  await writeFile(progressFilePath, JSON.stringify(progress, undefined, 4));
96572
96568
  }
96573
96569
  }
96570
+ function encodePathSegments(path) {
96571
+ return path
96572
+ .split("/")
96573
+ .map(segment => encodeURIComponent(segment))
96574
+ .join("/");
96575
+ }
96576
+ function encodeRepoSlug(modelSlug) {
96577
+ return modelSlug
96578
+ .split("/")
96579
+ .map(segment => encodeURIComponent(segment))
96580
+ .join("/");
96581
+ }
96582
+ function parseModelRevision(modelSlugWithRevision) {
96583
+ const revisionIndex = modelSlugWithRevision.indexOf("@");
96584
+ if (revisionIndex === -1) {
96585
+ return { modelSlug: modelSlugWithRevision, revision: "main" };
96586
+ }
96587
+ return {
96588
+ modelSlug: modelSlugWithRevision.slice(0, revisionIndex),
96589
+ revision: modelSlugWithRevision.slice(revisionIndex + 1)
96590
+ };
96591
+ }
96592
+ function getDownloadPaths({ filePath, targetDirectory }) {
96593
+ const finalPath = join(targetDirectory, filePath);
96594
+ return {
96595
+ finalPath,
96596
+ partialPath: `${finalPath}.partial`
96597
+ };
96598
+ }
96599
+ function getResolveURL({ filePath, modelSlug, revision }) {
96600
+ const encodedRepo = encodeRepoSlug(modelSlug);
96601
+ const encodedRevision = encodeURIComponent(revision);
96602
+ const encodedPath = encodePathSegments(filePath);
96603
+ return `https://huggingface.co/${encodedRepo}/resolve/${encodedRevision}/${encodedPath}`;
96604
+ }
96605
+ function getResolveDownloadURL({ filePath, modelSlug, revision }) {
96606
+ const baseUrl = getResolveURL({ filePath, modelSlug, revision });
96607
+ const resolvedUrl = new URL(baseUrl);
96608
+ resolvedUrl.searchParams.set("download", "1");
96609
+ return resolvedUrl.toString();
96610
+ }
96611
+ class RangeNotSupportedError extends Error {
96612
+ constructor(message) {
96613
+ super(message);
96614
+ this.name = "RangeNotSupportedError";
96615
+ }
96616
+ }
96617
+ function getAuthHeaders(accessToken) {
96618
+ if (!accessToken) {
96619
+ return {};
96620
+ }
96621
+ return {
96622
+ Authorization: `Bearer ${accessToken}`
96623
+ };
96624
+ }
96625
+ function shouldSendAuthHeader(url) {
96626
+ try {
96627
+ const hostname = new URL(url).hostname.toLowerCase();
96628
+ return hostname.endsWith("huggingface.co") || hostname.endsWith("hf.co");
96629
+ }
96630
+ catch {
96631
+ return false;
96632
+ }
96633
+ }
96634
+ function parseContentRangeTotal(contentRange) {
96635
+ if (!contentRange) {
96636
+ return null;
96637
+ }
96638
+ const totalMatch = /\/(\d+)$/.exec(contentRange);
96639
+ if (!totalMatch) {
96640
+ return null;
96641
+ }
96642
+ const totalSize = Number(totalMatch[1]);
96643
+ return Number.isFinite(totalSize) ? totalSize : null;
96644
+ }
96645
+ async function getDownloadURL({ accessToken, filePath, modelSlug, revision }) {
96646
+ const url = getResolveDownloadURL({ filePath, modelSlug, revision });
96647
+ try {
96648
+ const response = await undiciExports.fetch(url, {
96649
+ method: "GET",
96650
+ redirect: "manual",
96651
+ headers: getAuthHeaders(accessToken)
96652
+ });
96653
+ try {
96654
+ if (response.status >= 300 && response.status < 400) {
96655
+ const location = response.headers.get("location");
96656
+ if (location) {
96657
+ return { reason: null, status: response.status, url: location };
96658
+ }
96659
+ }
96660
+ if (response.ok) {
96661
+ return { reason: null, status: response.status, url: response.url };
96662
+ }
96663
+ let responseBody = "<unavailable>";
96664
+ try {
96665
+ responseBody = await response.text();
96666
+ }
96667
+ catch {
96668
+ responseBody = "<failed to read body>";
96669
+ }
96670
+ if (responseBody.length > 2000) {
96671
+ responseBody = responseBody.slice(0, 2000);
96672
+ }
96673
+ console.warn(`Resolve request failed body for ${filePath}: ${responseBody}`);
96674
+ return {
96675
+ reason: `Resolve request failed with status ${response.status}`,
96676
+ status: response.status,
96677
+ url: null
96678
+ };
96679
+ }
96680
+ finally {
96681
+ if (response.body && response.bodyUsed === false && response.body.locked === false) {
96682
+ await response.body.cancel();
96683
+ }
96684
+ }
96685
+ }
96686
+ catch (error) {
96687
+ const parsed = asError(error);
96688
+ return {
96689
+ reason: `Resolve request failed: ${parsed.message}`,
96690
+ status: null,
96691
+ url: null
96692
+ };
96693
+ }
96694
+ }
96695
+ async function getRangeInfo({ accessToken, filePath, fileSize, modelSlug, revision }) {
96696
+ const downloadUrlInfo = await getDownloadURL({
96697
+ accessToken,
96698
+ filePath,
96699
+ modelSlug,
96700
+ revision
96701
+ });
96702
+ if (!downloadUrlInfo.url) {
96703
+ return {
96704
+ reason: downloadUrlInfo.reason ?? "Resolve request failed",
96705
+ supportsRanges: false,
96706
+ totalSize: fileSize
96707
+ };
96708
+ }
96709
+ try {
96710
+ const response = await undiciExports.fetch(downloadUrlInfo.url, {
96711
+ method: "GET",
96712
+ headers: {
96713
+ ...(shouldSendAuthHeader(downloadUrlInfo.url) ? getAuthHeaders(accessToken) : {}),
96714
+ Range: "bytes=0-0"
96715
+ }
96716
+ });
96717
+ try {
96718
+ if (response.status === 206) {
96719
+ const totalSize = parseContentRangeTotal(response.headers.get("content-range"));
96720
+ return {
96721
+ reason: null,
96722
+ supportsRanges: true,
96723
+ totalSize: totalSize ?? fileSize
96724
+ };
96725
+ }
96726
+ if (response.status === 200) {
96727
+ return {
96728
+ reason: "Server returned 200 to range probe",
96729
+ supportsRanges: false,
96730
+ totalSize: fileSize
96731
+ };
96732
+ }
96733
+ return {
96734
+ reason: `Range probe failed with status ${response.status}`,
96735
+ supportsRanges: false,
96736
+ totalSize: fileSize
96737
+ };
96738
+ }
96739
+ finally {
96740
+ await response.body?.cancel();
96741
+ }
96742
+ }
96743
+ catch (error) {
96744
+ const parsed = asError(error);
96745
+ return {
96746
+ reason: `Range probe failed: ${parsed.message}`,
96747
+ supportsRanges: false,
96748
+ totalSize: fileSize
96749
+ };
96750
+ }
96751
+ }
96752
+ async function downloadFileFull({ accessToken, filePath, fileSize, modelSlug, targetDirectory }) {
96753
+ const { finalPath, partialPath } = getDownloadPaths({ filePath, targetDirectory });
96754
+ let lastError = null;
96755
+ for (let attempt = 1; attempt <= DOWNLOAD_RETRY_ATTEMPTS_FULL; attempt++) {
96756
+ try {
96757
+ console.log("Downloading:", filePath, fileSize, `(attempt ${attempt})`);
96758
+ await mkdir(dirname(finalPath), { recursive: true });
96759
+ if (existsSync(partialPath)) {
96760
+ await unlink(partialPath);
96761
+ }
96762
+ const response = await downloadFile({
96763
+ accessToken,
96764
+ repo: modelSlug,
96765
+ path: filePath
96766
+ });
96767
+ if (!response) {
96768
+ throw new Error(`Requested file did not return a valid response: ${filePath}`);
96769
+ }
96770
+ const input = Readable.fromWeb(response.stream());
96771
+ const meter = watchStreamProgress(25 * 1024 * 1024); // 25 MiB intervals
96772
+ const output = createWriteStream(partialPath, { flags: "w" });
96773
+ let progressTimeout = null;
96774
+ let lastPercentage = "0.0";
96775
+ let lastProgressBytes = 0;
96776
+ const resetProgressTimeout = () => {
96777
+ clearTimeout(progressTimeout);
96778
+ progressTimeout = setTimeout(() => {
96779
+ input.destroy(new Error(`Timed out with no progress for ${DOWNLOAD_PROGRESS_TIMEOUT}ms while downloading ${filePath}. Last progress: ${lastPercentage}% (${lastProgressBytes} / ${fileSize})`));
96780
+ }, DOWNLOAD_PROGRESS_TIMEOUT);
96781
+ };
96782
+ input.on("data", resetProgressTimeout);
96783
+ resetProgressTimeout();
96784
+ meter.progress.on("progress", (totalBytes) => {
96785
+ lastProgressBytes = totalBytes;
96786
+ const percentComplete = ((totalBytes / fileSize) * 100).toFixed(1);
96787
+ if (lastPercentage !== percentComplete) {
96788
+ console.log(` => ${percentComplete}% (${totalBytes} / ${fileSize})`);
96789
+ }
96790
+ lastPercentage = percentComplete;
96791
+ });
96792
+ try {
96793
+ await pipeline(input, meter, output);
96794
+ }
96795
+ finally {
96796
+ clearTimeout(progressTimeout);
96797
+ }
96798
+ await rename(partialPath, finalPath);
96799
+ return;
96800
+ }
96801
+ catch (error) {
96802
+ lastError = asError(error);
96803
+ if (attempt < DOWNLOAD_RETRY_ATTEMPTS_FULL) {
96804
+ console.warn(`Retrying full download (${attempt}/${DOWNLOAD_RETRY_ATTEMPTS_FULL}) for ${filePath} due to error: ${lastError.message}`);
96805
+ continue;
96806
+ }
96807
+ }
96808
+ }
96809
+ const errorMessage = `Failed downloading ${filePath} (${fileSize} bytes) after ${DOWNLOAD_RETRY_ATTEMPTS_FULL} attempts. Last error: ${lastError?.message ?? "Unknown error"}`;
96810
+ throw new Error(errorMessage);
96811
+ }
96812
+ async function downloadFileWithRange({ accessToken, filePath, fileSize, modelSlug, revision, targetDirectory }) {
96813
+ const { finalPath, partialPath } = getDownloadPaths({ filePath, targetDirectory });
96814
+ let lastError = null;
96815
+ for (let attempt = 1; attempt <= DOWNLOAD_RETRY_ATTEMPTS_RANGE; attempt++) {
96816
+ let startOffset = 0;
96817
+ if (existsSync(partialPath)) {
96818
+ const currentStats = await stat(partialPath);
96819
+ startOffset = currentStats.size;
96820
+ if (startOffset > fileSize) {
96821
+ await unlink(partialPath);
96822
+ startOffset = 0;
96823
+ }
96824
+ if (startOffset === fileSize) {
96825
+ await rename(partialPath, finalPath);
96826
+ return;
96827
+ }
96828
+ }
96829
+ try {
96830
+ const resumeLabel = startOffset > 0 ? `resuming at ${startOffset}` : "starting";
96831
+ console.log("Downloading:", filePath, fileSize, `(attempt ${attempt}, ${resumeLabel})`);
96832
+ await mkdir(dirname(finalPath), { recursive: true });
96833
+ const downloadUrlInfo = await getDownloadURL({
96834
+ accessToken,
96835
+ filePath,
96836
+ modelSlug,
96837
+ revision
96838
+ });
96839
+ if (!downloadUrlInfo.url) {
96840
+ if (downloadUrlInfo.status === 400) {
96841
+ throw new RangeNotSupportedError(downloadUrlInfo.reason ?? "Resolve request failed");
96842
+ }
96843
+ throw new Error(downloadUrlInfo.reason ?? "Resolve request failed");
96844
+ }
96845
+ const response = await undiciExports.fetch(downloadUrlInfo.url, {
96846
+ headers: {
96847
+ ...(shouldSendAuthHeader(downloadUrlInfo.url)
96848
+ ? getAuthHeaders(accessToken)
96849
+ : {}),
96850
+ Range: `bytes=${startOffset}-`
96851
+ }
96852
+ });
96853
+ if (!response.ok) {
96854
+ let responseBody = "<unavailable>";
96855
+ try {
96856
+ responseBody = await response.text();
96857
+ }
96858
+ catch {
96859
+ responseBody = "<failed to read body>";
96860
+ }
96861
+ if (responseBody.length > 2000) {
96862
+ responseBody = responseBody.slice(0, 2000);
96863
+ }
96864
+ console.warn(`Range request failed response body for ${filePath}: ${responseBody}`);
96865
+ throw new Error(`Range request failed with status ${response.status} for ${filePath}`);
96866
+ }
96867
+ if (startOffset > 0 && response.status !== 206) {
96868
+ throw new RangeNotSupportedError(`Server did not honor range request (status ${response.status})`);
96869
+ }
96870
+ if (!response.body) {
96871
+ throw new Error(`Range request returned no body for ${filePath}`);
96872
+ }
96873
+ const input = Readable.fromWeb(response.body);
96874
+ const meter = watchStreamProgress(25 * 1024 * 1024); // 25 MiB intervals
96875
+ const output = createWriteStream(partialPath, { flags: "a" });
96876
+ let progressTimeout = null;
96877
+ let lastPercentage = ((startOffset / fileSize) * 100).toFixed(1);
96878
+ let lastProgressBytes = startOffset;
96879
+ const resetProgressTimeout = () => {
96880
+ clearTimeout(progressTimeout);
96881
+ progressTimeout = setTimeout(() => {
96882
+ input.destroy(new Error(`Timed out with no progress for ${DOWNLOAD_PROGRESS_TIMEOUT}ms while downloading ${filePath}. Last progress: ${lastPercentage}% (${lastProgressBytes} / ${fileSize})`));
96883
+ }, DOWNLOAD_PROGRESS_TIMEOUT);
96884
+ };
96885
+ input.on("data", resetProgressTimeout);
96886
+ resetProgressTimeout();
96887
+ meter.progress.on("progress", (totalBytes) => {
96888
+ lastProgressBytes = startOffset + totalBytes;
96889
+ const percentComplete = ((lastProgressBytes / fileSize) * 100).toFixed(1);
96890
+ if (lastPercentage !== percentComplete) {
96891
+ console.log(` => ${percentComplete}% (${lastProgressBytes} / ${fileSize})`);
96892
+ }
96893
+ lastPercentage = percentComplete;
96894
+ });
96895
+ try {
96896
+ await pipeline(input, meter, output);
96897
+ }
96898
+ finally {
96899
+ clearTimeout(progressTimeout);
96900
+ }
96901
+ const updatedStats = await stat(partialPath);
96902
+ if (updatedStats.size < fileSize) {
96903
+ throw new Error(`Download incomplete for ${filePath}. Received ${updatedStats.size} / ${fileSize} bytes`);
96904
+ }
96905
+ await rename(partialPath, finalPath);
96906
+ return;
96907
+ }
96908
+ catch (error) {
96909
+ lastError = asError(error);
96910
+ if (lastError instanceof RangeNotSupportedError) {
96911
+ throw lastError;
96912
+ }
96913
+ if (attempt < DOWNLOAD_RETRY_ATTEMPTS_RANGE) {
96914
+ console.warn(`Retrying range download (${attempt}/${DOWNLOAD_RETRY_ATTEMPTS_RANGE}) for ${filePath} due to error: ${lastError.message}`);
96915
+ continue;
96916
+ }
96917
+ }
96918
+ }
96919
+ const errorMessage = `Failed downloading ${filePath} (${fileSize} bytes) after ${DOWNLOAD_RETRY_ATTEMPTS_RANGE} attempts. Last error: ${lastError?.message ?? "Unknown error"}`;
96920
+ throw new Error(errorMessage);
96921
+ }
96574
96922
 
96575
96923
  const balanced = (a, b, str) => {
96576
96924
  const ma = a instanceof RegExp ? maybeMatch(a, str) : a;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@infersec/conduit",
3
3
  "description": "End user conduit agent for connecting local LLMs to the cloud.",
4
- "version": "1.6.0",
4
+ "version": "1.6.2",
5
5
  "bin": {
6
6
  "infersec-conduit": "./dist/cli.js"
7
7
  },