@atomic-chat/core 0.21.0 → 0.21.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/backend/advisor/advisor.js +11 -2
- package/dist/backend/advisor/advisor.js.map +1 -1
- package/dist/backend/install/cuda-guard.d.ts +62 -0
- package/dist/backend/install/cuda-guard.js +80 -0
- package/dist/backend/install/cuda-guard.js.map +1 -0
- package/dist/backend/install/cuda-runtime-source.d.ts +76 -0
- package/dist/backend/install/cuda-runtime-source.js +294 -0
- package/dist/backend/install/cuda-runtime-source.js.map +1 -0
- package/dist/backend/install/index.d.ts +3 -0
- package/dist/backend/install/index.js +3 -0
- package/dist/backend/install/index.js.map +1 -1
- package/dist/backend/install/runtime-backend.d.ts +30 -3
- package/dist/backend/install/runtime-backend.js +106 -28
- package/dist/backend/install/runtime-backend.js.map +1 -1
- package/dist/backend/install/service.d.ts +42 -24
- package/dist/backend/install/service.js +176 -31
- package/dist/backend/install/service.js.map +1 -1
- package/dist/backend/install/windows-launch-check.d.ts +72 -0
- package/dist/backend/install/windows-launch-check.js +173 -0
- package/dist/backend/install/windows-launch-check.js.map +1 -0
- package/dist/backend/installed/installed.d.ts +13 -0
- package/dist/backend/installed/installed.js +32 -0
- package/dist/backend/installed/installed.js.map +1 -1
- package/dist/backend/select/bad-backends.d.ts +68 -0
- package/dist/backend/select/bad-backends.js +136 -0
- package/dist/backend/select/bad-backends.js.map +1 -0
- package/dist/backend/select/features.d.ts +18 -1
- package/dist/backend/select/features.js +29 -1
- package/dist/backend/select/features.js.map +1 -1
- package/dist/backend/select/index.d.ts +1 -0
- package/dist/backend/select/index.js +1 -0
- package/dist/backend/select/index.js.map +1 -1
- package/dist/backend/turboquant.d.ts +8 -0
- package/dist/backend/turboquant.js +37 -9
- package/dist/backend/turboquant.js.map +1 -1
- package/dist/cli/main.d.ts +1 -1
- package/dist/contracts/diagnostics.d.ts +21 -0
- package/dist/contracts/diagnostics.js +71 -0
- package/dist/contracts/diagnostics.js.map +1 -0
- package/dist/contracts/errors.d.ts +18 -76
- package/dist/contracts/errors.js +145 -2
- package/dist/contracts/errors.js.map +1 -1
- package/dist/contracts/hardware.d.ts +8 -0
- package/dist/contracts/index.d.ts +2 -0
- package/dist/contracts/index.js +2 -0
- package/dist/contracts/index.js.map +1 -1
- package/dist/contracts/load-diag.d.ts +34 -0
- package/dist/contracts/load-diag.js +48 -0
- package/dist/contracts/load-diag.js.map +1 -0
- package/dist/core/atomic-core.d.ts +1 -1
- package/dist/core/atomic-core.js +2 -1
- package/dist/core/atomic-core.js.map +1 -1
- package/dist/core/create.js +25 -15
- package/dist/core/create.js.map +1 -1
- package/dist/core/managed-environment.d.ts +2 -0
- package/dist/core/managed-environment.js +2 -0
- package/dist/core/managed-environment.js.map +1 -1
- package/dist/decision/service.d.ts +2 -23
- package/dist/decision/service.js +27 -0
- package/dist/decision/service.js.map +1 -1
- package/dist/decision/wiring.d.ts +2 -0
- package/dist/decision/wiring.js +1 -6
- package/dist/decision/wiring.js.map +1 -1
- package/dist/diffusion/errors.js +3 -3
- package/dist/diffusion/errors.js.map +1 -1
- package/dist/diffusion/jobs.js +1 -0
- package/dist/diffusion/jobs.js.map +1 -1
- package/dist/diffusion/remote-job.js +1 -0
- package/dist/diffusion/remote-job.js.map +1 -1
- package/dist/diffusion/service.d.ts +2 -6
- package/dist/diffusion/service.js +1 -0
- package/dist/diffusion/service.js.map +1 -1
- package/dist/diffusion/session.d.ts +2 -5
- package/dist/diffusion/session.js +1 -0
- package/dist/diffusion/session.js.map +1 -1
- package/dist/diffusion/wiring.d.ts +2 -0
- package/dist/diffusion/wiring.js +1 -5
- package/dist/diffusion/wiring.js.map +1 -1
- package/dist/downloads/archive.js +8 -3
- package/dist/downloads/archive.js.map +1 -1
- package/dist/downloads/disk.d.ts +18 -0
- package/dist/downloads/disk.js +32 -1
- package/dist/downloads/disk.js.map +1 -1
- package/dist/downloads/downloader.d.ts +2 -18
- package/dist/downloads/downloader.js +208 -97
- package/dist/downloads/downloader.js.map +1 -1
- package/dist/downloads/fs-retry.d.ts +27 -0
- package/dist/downloads/fs-retry.js +40 -0
- package/dist/downloads/fs-retry.js.map +1 -0
- package/dist/downloads/index.d.ts +1 -0
- package/dist/downloads/index.js +1 -0
- package/dist/downloads/index.js.map +1 -1
- package/dist/downloads/protocol.d.ts +6 -2
- package/dist/downloads/protocol.js +27 -5
- package/dist/downloads/protocol.js.map +1 -1
- package/dist/embedding/service.d.ts +2 -18
- package/dist/embedding/service.js +21 -1
- package/dist/embedding/service.js.map +1 -1
- package/dist/embedding/wiring.d.ts +2 -0
- package/dist/embedding/wiring.js +1 -6
- package/dist/embedding/wiring.js.map +1 -1
- package/dist/hardware/index.d.ts +1 -0
- package/dist/hardware/index.js +1 -0
- package/dist/hardware/index.js.map +1 -1
- package/dist/hardware/probe-common.d.ts +9 -1
- package/dist/hardware/probe-common.js.map +1 -1
- package/dist/hardware/probe-windows.d.ts +10 -2
- package/dist/hardware/probe-windows.js +65 -10
- package/dist/hardware/probe-windows.js.map +1 -1
- package/dist/hardware/probe.js +1 -1
- package/dist/hardware/probe.js.map +1 -1
- package/dist/hardware/service.d.ts +11 -0
- package/dist/hardware/service.js +31 -4
- package/dist/hardware/service.js.map +1 -1
- package/dist/hardware/windows-registry.d.ts +80 -0
- package/dist/hardware/windows-registry.js +197 -0
- package/dist/hardware/windows-registry.js.map +1 -0
- package/dist/lock/instance-lock.js +7 -3
- package/dist/lock/instance-lock.js.map +1 -1
- package/dist/remote-access/manager.d.ts +2 -0
- package/dist/remote-access/manager.js +18 -2
- package/dist/remote-access/manager.js.map +1 -1
- package/dist/runtime/environment/service.d.ts +2 -14
- package/dist/runtime/environment/service.js +10 -0
- package/dist/runtime/environment/service.js.map +1 -1
- package/dist/runtime/environment/wiring.d.ts +2 -23
- package/dist/runtime/environment/wiring.js +1 -0
- package/dist/runtime/environment/wiring.js.map +1 -1
- package/dist/runtime/llamacpp/args.d.ts +11 -0
- package/dist/runtime/llamacpp/args.js +28 -3
- package/dist/runtime/llamacpp/args.js.map +1 -1
- package/dist/runtime/llamacpp/devices.d.ts +11 -0
- package/dist/runtime/llamacpp/devices.js +22 -0
- package/dist/runtime/llamacpp/devices.js.map +1 -1
- package/dist/runtime/llamacpp/errors.d.ts +34 -4
- package/dist/runtime/llamacpp/errors.js +105 -22
- package/dist/runtime/llamacpp/errors.js.map +1 -1
- package/dist/runtime/llamacpp/index.d.ts +1 -0
- package/dist/runtime/llamacpp/index.js +1 -0
- package/dist/runtime/llamacpp/index.js.map +1 -1
- package/dist/runtime/llamacpp/load-failure.d.ts +52 -0
- package/dist/runtime/llamacpp/load-failure.js +105 -0
- package/dist/runtime/llamacpp/load-failure.js.map +1 -0
- package/dist/runtime/llamacpp/load-plan.d.ts +5 -0
- package/dist/runtime/llamacpp/load-plan.js +34 -4
- package/dist/runtime/llamacpp/load-plan.js.map +1 -1
- package/dist/runtime/llamacpp/runtime.d.ts +24 -1
- package/dist/runtime/llamacpp/runtime.js +116 -27
- package/dist/runtime/llamacpp/runtime.js.map +1 -1
- package/dist/runtime/shared/env.js +13 -15
- package/dist/runtime/shared/env.js.map +1 -1
- package/dist/server/public/errors.d.ts +2 -0
- package/dist/server/public/errors.js +6 -2
- package/dist/server/public/errors.js.map +1 -1
- package/dist/server/public/forward.js +22 -18
- package/dist/server/public/forward.js.map +1 -1
- package/dist/settings/store.js +1 -1
- package/dist/settings/store.js.map +1 -1
- package/dist/telemetry/diagnostics.d.ts +14 -0
- package/dist/telemetry/diagnostics.js +289 -0
- package/dist/telemetry/diagnostics.js.map +1 -0
- package/dist/telemetry/envelope.d.ts +1 -1
- package/dist/telemetry/envelope.js +57 -28
- package/dist/telemetry/envelope.js.map +1 -1
- package/dist/telemetry/index.d.ts +1 -0
- package/dist/telemetry/index.js +1 -0
- package/dist/telemetry/index.js.map +1 -1
- package/dist/telemetry/policy.d.ts +1 -1
- package/dist/telemetry/policy.js +45 -2
- package/dist/telemetry/policy.js.map +1 -1
- package/dist/telemetry/reporter.d.ts +1 -0
- package/dist/telemetry/reporter.js +0 -0
- package/dist/telemetry/reporter.js.map +1 -1
- package/dist/telemetry/reports.d.ts +2 -7
- package/dist/telemetry/reports.js +34 -29
- package/dist/telemetry/reports.js.map +1 -1
- package/dist/telemetry/stack.d.ts +1 -1
- package/dist/telemetry/stack.js +8 -1
- package/dist/telemetry/stack.js.map +1 -1
- package/dist/telemetry/subscribe.d.ts +1 -1
- package/dist/telemetry/subscribe.js +7 -5
- package/dist/telemetry/subscribe.js.map +1 -1
- package/dist/telemetry/types.d.ts +3 -2
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"archive.js","sourceRoot":"","sources":["../../src/downloads/archive.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,iBAAiB,EAAE,MAAM,SAAS,CAAA;AAC3C,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,EAAE,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAA;AAC1E,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,WAAW,CAAA;AAC1E,OAAO,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAA;AAC/C,OAAO,EAAE,CAAC,IAAI,UAAU,EAAE,MAAM,KAAK,CAAA;AACrC,OAAO,KAAK,MAAM,OAAO,CAAA;
|
|
1
|
+
{"version":3,"file":"archive.js","sourceRoot":"","sources":["../../src/downloads/archive.ts"],"names":[],"mappings":"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"}
|
package/dist/downloads/disk.d.ts
CHANGED
|
@@ -14,6 +14,24 @@ import type { DiskErrorTag } from '../contracts/index.js';
|
|
|
14
14
|
export declare function classifyIoError(error: unknown): DiskErrorTag;
|
|
15
15
|
/** `Error: [<tag>] <message>` — the shape the frontend parses. */
|
|
16
16
|
export declare function diskErrToString(error: unknown): string;
|
|
17
|
+
/** The largest file a FAT/FAT32 volume can hold: 4 GiB minus one byte. */
|
|
18
|
+
export declare const FAT32_MAX_FILE_BYTES: number;
|
|
19
|
+
/**
|
|
20
|
+
* The tag of a failed write of `length` bytes at `offset`. FAT32 refuses exactly the write that takes
|
|
21
|
+
* a file past 4 GiB − 1, and Windows words that refusal as a full disk (or an error libuv has no name
|
|
22
|
+
* for): a write that crosses that line and fails as anything but a permission or a lock is the
|
|
23
|
+
* volume's file-size limit. Every other failed write is tagged as `classifyIoError` tags it.
|
|
24
|
+
*/
|
|
25
|
+
export declare function writeFaultTag(error: unknown, offset: number, length: number): DiskErrorTag;
|
|
26
|
+
/** `diskErrToString` for a failed write, with the FAT32 rule of `writeFaultTag`. */
|
|
27
|
+
export declare function diskWriteErrToString(error: unknown, offset: number, length: number): string;
|
|
28
|
+
/**
|
|
29
|
+
* The tag of a rename or removal that still failed after `retryTransientFs` waited. On Windows a
|
|
30
|
+
* denial on a directory this process has just written is a handle someone else holds (antivirus,
|
|
31
|
+
* the indexer, a server running from the old copy), not a missing permission: the process could
|
|
32
|
+
* write there a moment ago. Elsewhere, and for every other code, `classifyIoError` decides.
|
|
33
|
+
*/
|
|
34
|
+
export declare function heldFileFaultTag(error: unknown, platform: NodeJS.Platform | string): DiskErrorTag;
|
|
17
35
|
/** Same shape for a preflight refusal that has no fs error behind it. */
|
|
18
36
|
export declare function diskFaultMessage(tag: DiskErrorTag, detail: string): string;
|
|
19
37
|
/** Bytes never consumed on top of the download itself (a volume at zero free bytes kills the app). */
|
package/dist/downloads/disk.js
CHANGED
|
@@ -9,10 +9,12 @@
|
|
|
9
9
|
* already maps Win32 codes (ERROR_DISK_FULL → ENOSPC, ERROR_SHARING_VIOLATION → EBUSY, …), so one
|
|
10
10
|
* table covers both sides of the Rust `cfg(unix)` / `cfg(windows)` split.
|
|
11
11
|
*/
|
|
12
|
+
import { isTransientFsError } from './fs-retry.js';
|
|
12
13
|
const CODE_TO_TAG = {
|
|
13
14
|
ENOSPC: 'disk_full',
|
|
14
15
|
EDQUOT: 'disk_full',
|
|
15
|
-
|
|
16
|
+
// "File too large": the volume's own size limit for one file (FAT32's 4 GiB), not a full disk.
|
|
17
|
+
EFBIG: 'disk_fs_limit',
|
|
16
18
|
EACCES: 'disk_permission',
|
|
17
19
|
EPERM: 'disk_permission',
|
|
18
20
|
EROFS: 'disk_permission',
|
|
@@ -36,6 +38,35 @@ export function diskErrToString(error) {
|
|
|
36
38
|
const message = error instanceof Error ? error.message : String(error);
|
|
37
39
|
return `Error: [${classifyIoError(error)}] ${message}`;
|
|
38
40
|
}
|
|
41
|
+
/** The largest file a FAT/FAT32 volume can hold: 4 GiB minus one byte. */
|
|
42
|
+
export const FAT32_MAX_FILE_BYTES = 2 ** 32 - 1;
|
|
43
|
+
/**
|
|
44
|
+
* The tag of a failed write of `length` bytes at `offset`. FAT32 refuses exactly the write that takes
|
|
45
|
+
* a file past 4 GiB − 1, and Windows words that refusal as a full disk (or an error libuv has no name
|
|
46
|
+
* for): a write that crosses that line and fails as anything but a permission or a lock is the
|
|
47
|
+
* volume's file-size limit. Every other failed write is tagged as `classifyIoError` tags it.
|
|
48
|
+
*/
|
|
49
|
+
export function writeFaultTag(error, offset, length) {
|
|
50
|
+
const tag = classifyIoError(error);
|
|
51
|
+
const crosses = offset <= FAT32_MAX_FILE_BYTES && offset + length > FAT32_MAX_FILE_BYTES;
|
|
52
|
+
return crosses && (tag === 'disk_full' || tag === 'disk_io' || tag === 'disk_fs_limit')
|
|
53
|
+
? 'disk_fs_limit'
|
|
54
|
+
: tag;
|
|
55
|
+
}
|
|
56
|
+
/** `diskErrToString` for a failed write, with the FAT32 rule of `writeFaultTag`. */
|
|
57
|
+
export function diskWriteErrToString(error, offset, length) {
|
|
58
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
59
|
+
return `Error: [${writeFaultTag(error, offset, length)}] ${message}`;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* The tag of a rename or removal that still failed after `retryTransientFs` waited. On Windows a
|
|
63
|
+
* denial on a directory this process has just written is a handle someone else holds (antivirus,
|
|
64
|
+
* the indexer, a server running from the old copy), not a missing permission: the process could
|
|
65
|
+
* write there a moment ago. Elsewhere, and for every other code, `classifyIoError` decides.
|
|
66
|
+
*/
|
|
67
|
+
export function heldFileFaultTag(error, platform) {
|
|
68
|
+
return platform === 'win32' && isTransientFsError(error) ? 'disk_file_locked' : classifyIoError(error);
|
|
69
|
+
}
|
|
39
70
|
/** Same shape for a preflight refusal that has no fs error behind it. */
|
|
40
71
|
export function diskFaultMessage(tag, detail) {
|
|
41
72
|
return `Error: [${tag}] ${detail}`;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"disk.js","sourceRoot":"","sources":["../../src/downloads/disk.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;
|
|
1
|
+
{"version":3,"file":"disk.js","sourceRoot":"","sources":["../../src/downloads/disk.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,21 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
* Resumable multi-file downloader. Port of `_download_files_internal` / `download_single_file` in
|
|
3
|
-
* `src-tauri/src/core/downloads/helpers.rs` and the task registry in `commands.rs`.
|
|
4
|
-
*
|
|
5
|
-
* Behaviour that is a contract with the app (PLAN.md §8.2 "Downloads"):
|
|
6
|
-
* - `save_path` is relative to `<data>` and must stay inside it (symlinked prefixes compared resolved)
|
|
7
|
-
* - `.tmp` + `.url` sidecars; resume only when `resume` is set, the `.tmp` exists and `.url` matches
|
|
8
|
-
* - `Range: bytes=N-` → 206 + validated `Content-Range`; 200/416 → restart from 0; 408/429/5xx retry
|
|
9
|
-
* - 5 retries per stall, counter reset after every 1 MiB of fresh progress
|
|
10
|
-
* - combined progress `{transferred,total}` after resume, every 10 MiB per file, per file end, task end
|
|
11
|
-
* - verification (size, sha256) after all files; on failure the file and its directory (non-recursive)
|
|
12
|
-
* are removed and the task fails; cancel keeps every partial and finished file
|
|
13
|
-
* - preflight: Windows path limit, free space with 512 MiB headroom (skipped when unknown)
|
|
14
|
-
* - every fs error is rendered `Error: [disk_*] …`
|
|
15
|
-
*
|
|
16
|
-
* I/O is injected (`fetch`, fs, free-space probe, sleep) so the whole flow is testable against a
|
|
17
|
-
* scripted HTTP server without touching the network or the real data folder.
|
|
18
|
-
*/
|
|
1
|
+
import type { FailureObserver } from '../contracts/index.js';
|
|
19
2
|
import type { CoreEvents, DownloadProgress } from '../contracts/index.js';
|
|
20
3
|
import type { ProxyConfig } from './protocol.js';
|
|
21
4
|
import type { VerifyDeps } from './verify.js';
|
|
@@ -34,6 +17,7 @@ export interface DownloadOptions {
|
|
|
34
17
|
}
|
|
35
18
|
export declare const DOWNLOAD_CANCELLED = "Download cancelled";
|
|
36
19
|
export interface DownloaderDeps {
|
|
20
|
+
onFailure?: FailureObserver;
|
|
37
21
|
dataFolder: string;
|
|
38
22
|
platform: NodeJS.Platform;
|
|
39
23
|
fetch: typeof fetch;
|
|
@@ -19,11 +19,67 @@
|
|
|
19
19
|
import { createWriteStream } from 'node:fs';
|
|
20
20
|
import { mkdir, readFile, realpath, rename, rm, rmdir, stat, statfs, writeFile } from 'node:fs/promises';
|
|
21
21
|
import { dirname, isAbsolute, join, relative, resolve } from 'node:path';
|
|
22
|
-
import { checkFreeSpace, checkPathWithinLimit, diskErrToString, remainingBytes } from './disk.js';
|
|
22
|
+
import { checkFreeSpace, checkPathWithinLimit, diskErrToString, diskWriteErrToString, remainingBytes, } from './disk.js';
|
|
23
23
|
import { classifyDownloadStatus, classifyResumeStatus, DownloadRequestError, downloadStage, expectedDownloadSize, HEAD_TIMEOUT_MS, MAX_STREAM_RETRIES, PROGRESS_EMIT_INTERVAL_BYTES, RETRY_RESET_PROGRESS_BYTES, retryDelayMs, shouldBypassProxy, sidecarPath, validateContentRange, validateProxyConfig, } from './protocol.js';
|
|
24
24
|
import { policyFetchFor } from './proxy-fetch.js';
|
|
25
25
|
import { verifyDownloadedFile } from './verify.js';
|
|
26
26
|
export const DOWNLOAD_CANCELLED = 'Download cancelled';
|
|
27
|
+
/**
|
|
28
|
+
* Open a `.tmp` write stream with an error listener attached before `open` settles on the threadpool,
|
|
29
|
+
* and resolve `close()` only once the underlying file descriptor has closed.
|
|
30
|
+
*/
|
|
31
|
+
async function openWriteStream(path, flags, disk) {
|
|
32
|
+
const writer = createWriteStream(path, { flags });
|
|
33
|
+
let streamError;
|
|
34
|
+
writer.on('error', (err) => {
|
|
35
|
+
streamError ??= err;
|
|
36
|
+
});
|
|
37
|
+
await new Promise((ok, fail) => {
|
|
38
|
+
const onOpen = () => {
|
|
39
|
+
writer.off('error', onError);
|
|
40
|
+
ok();
|
|
41
|
+
};
|
|
42
|
+
const onError = (err) => {
|
|
43
|
+
writer.off('open', onOpen);
|
|
44
|
+
fail(disk(err));
|
|
45
|
+
};
|
|
46
|
+
writer.once('open', onOpen);
|
|
47
|
+
writer.once('error', onError);
|
|
48
|
+
});
|
|
49
|
+
let closing;
|
|
50
|
+
const close = () => {
|
|
51
|
+
if (closing)
|
|
52
|
+
return closing;
|
|
53
|
+
closing = new Promise((ok, fail) => {
|
|
54
|
+
const finish = () => (streamError ? fail(disk(streamError)) : ok());
|
|
55
|
+
if (writer.closed)
|
|
56
|
+
return finish();
|
|
57
|
+
writer.once('close', finish);
|
|
58
|
+
if (!writer.destroyed) {
|
|
59
|
+
writer.end((err) => {
|
|
60
|
+
if (err)
|
|
61
|
+
streamError ??= err;
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
});
|
|
65
|
+
return closing;
|
|
66
|
+
};
|
|
67
|
+
const write = (chunk, offset) => new Promise((ok, fail) => {
|
|
68
|
+
if (streamError)
|
|
69
|
+
return fail(disk(streamError));
|
|
70
|
+
writer.write(chunk, (err) => {
|
|
71
|
+
if (err) {
|
|
72
|
+
streamError ??= err;
|
|
73
|
+
fail(offset === undefined
|
|
74
|
+
? disk(err)
|
|
75
|
+
: new Error(diskWriteErrToString(err, offset, chunk.byteLength), { cause: err }));
|
|
76
|
+
}
|
|
77
|
+
else
|
|
78
|
+
ok();
|
|
79
|
+
});
|
|
80
|
+
});
|
|
81
|
+
return { write, close };
|
|
82
|
+
}
|
|
27
83
|
export async function defaultAvailableSpace(path) {
|
|
28
84
|
let probe = path;
|
|
29
85
|
for (;;) {
|
|
@@ -77,6 +133,18 @@ const isInside = (child, parent) => {
|
|
|
77
133
|
const rel = relative(parent, child);
|
|
78
134
|
return rel === '' || (!rel.startsWith('..') && !isAbsolute(rel));
|
|
79
135
|
};
|
|
136
|
+
// Keep the historical Error and message while allowing every observing boundary to classify it.
|
|
137
|
+
function preflightFailure(message, reason) {
|
|
138
|
+
return Object.defineProperty(new Error(message), 'diagnostic', {
|
|
139
|
+
value: {
|
|
140
|
+
component: 'downloads',
|
|
141
|
+
operation: 'download',
|
|
142
|
+
stage: 'validate',
|
|
143
|
+
reason,
|
|
144
|
+
category: reason === 'invalid_request' ? 'expected' : 'operational',
|
|
145
|
+
},
|
|
146
|
+
});
|
|
147
|
+
}
|
|
80
148
|
export class Downloader {
|
|
81
149
|
tasks = new Map();
|
|
82
150
|
deps;
|
|
@@ -125,6 +193,11 @@ export class Downloader {
|
|
|
125
193
|
try {
|
|
126
194
|
await this.run(taskId, items, options, task.controller.signal);
|
|
127
195
|
}
|
|
196
|
+
catch (error) {
|
|
197
|
+
if (!task.controller.signal.aborted)
|
|
198
|
+
this.deps.onFailure?.(error, { component: 'downloads', operation: 'download' });
|
|
199
|
+
throw error;
|
|
200
|
+
}
|
|
128
201
|
finally {
|
|
129
202
|
if (this.tasks.get(taskId) === task)
|
|
130
203
|
this.tasks.delete(taskId);
|
|
@@ -141,7 +214,7 @@ export class Downloader {
|
|
|
141
214
|
if (item.proxy) {
|
|
142
215
|
const problem = validateProxyConfig(item.proxy);
|
|
143
216
|
if (problem)
|
|
144
|
-
throw
|
|
217
|
+
throw preflightFailure(`Error: ${problem}`, 'invalid_request');
|
|
145
218
|
}
|
|
146
219
|
}
|
|
147
220
|
// Preflight sizes (catalog size or HEAD; HEAD failures degrade to unknown).
|
|
@@ -157,9 +230,9 @@ export class Downloader {
|
|
|
157
230
|
const savePath = resolve(dataFolder, item.save_path);
|
|
158
231
|
const limit = checkPathWithinLimit(savePath, platform);
|
|
159
232
|
if (limit)
|
|
160
|
-
throw
|
|
233
|
+
throw preflightFailure(limit, 'disk_path_too_long');
|
|
161
234
|
if (!isInside(await canonicalizeExistingPrefix(savePath), resolvedRoot)) {
|
|
162
|
-
throw
|
|
235
|
+
throw preflightFailure(`Path ${savePath} is outside of Jan data folder ${dataFolder}`, 'invalid_request');
|
|
163
236
|
}
|
|
164
237
|
savePaths.push(savePath);
|
|
165
238
|
if (resume) {
|
|
@@ -173,7 +246,7 @@ export class Downloader {
|
|
|
173
246
|
}
|
|
174
247
|
const space = checkFreeSpace(await this.deps.availableSpace(dataFolder), remainingBytes(totalSize, partialSizes));
|
|
175
248
|
if (space)
|
|
176
|
-
throw
|
|
249
|
+
throw preflightFailure(space, 'disk_full');
|
|
177
250
|
const progress = new Map();
|
|
178
251
|
const emitProgress = () => {
|
|
179
252
|
const transferred = [...progress.values()].reduce((a, b) => a + b, 0);
|
|
@@ -184,14 +257,28 @@ export class Downloader {
|
|
|
184
257
|
task.progress = current;
|
|
185
258
|
this.deps.emit('download:progress', current);
|
|
186
259
|
};
|
|
187
|
-
const
|
|
260
|
+
const batch = new AbortController();
|
|
261
|
+
const batchSignal = AbortSignal.any([signal, batch.signal]);
|
|
262
|
+
let firstError;
|
|
263
|
+
let failed = false;
|
|
264
|
+
const settled = await Promise.allSettled(items.map((item, i) => this.downloadOne(item, savePaths[i], `${taskId}-${i}`, sizes.get(item.url) ?? 0, {
|
|
188
265
|
headers,
|
|
189
266
|
resume,
|
|
190
|
-
signal,
|
|
267
|
+
signal: batchSignal,
|
|
191
268
|
progress,
|
|
192
269
|
emitProgress,
|
|
193
270
|
reportStage,
|
|
271
|
+
}).catch((error) => {
|
|
272
|
+
if (!failed) {
|
|
273
|
+
failed = true;
|
|
274
|
+
firstError = error;
|
|
275
|
+
batch.abort();
|
|
276
|
+
}
|
|
277
|
+
throw error;
|
|
194
278
|
})));
|
|
279
|
+
if (failed)
|
|
280
|
+
throw firstError;
|
|
281
|
+
const results = settled.map((outcome) => outcome.value);
|
|
195
282
|
if (items.some((it) => it.sha256 != null || it.size != null)) {
|
|
196
283
|
const modelId = items.find((it) => it.model_id != null)?.model_id ??
|
|
197
284
|
(items[0] ? (dirname(items[0].save_path).split(/[\\/]/).pop() ?? 'unknown') : 'unknown');
|
|
@@ -260,7 +347,7 @@ export class Downloader {
|
|
|
260
347
|
catch (e) {
|
|
261
348
|
if (signal.aborted)
|
|
262
349
|
throw new Error(DOWNLOAD_CANCELLED);
|
|
263
|
-
throw new DownloadRequestError('retryable', e.message);
|
|
350
|
+
throw new DownloadRequestError('retryable', e.message, { cause: e });
|
|
264
351
|
}
|
|
265
352
|
if (startBytes > 0) {
|
|
266
353
|
if (res.status === 206) {
|
|
@@ -298,7 +385,7 @@ export class Downloader {
|
|
|
298
385
|
}
|
|
299
386
|
async downloadOne(item, savePath, fileId, fileSize, ctx) {
|
|
300
387
|
const { signal, headers, progress, emitProgress, reportStage } = ctx;
|
|
301
|
-
const disk = (e) => new Error(diskErrToString(e));
|
|
388
|
+
const disk = (e) => new Error(diskErrToString(e), { cause: e });
|
|
302
389
|
const fetchImpl = this.deps.fetchFor(item, this.deps.fetch);
|
|
303
390
|
if (item.proxy && shouldBypassProxy(item.url, item.proxy.no_proxy ?? []))
|
|
304
391
|
this.deps.log('info', `Bypassing proxy for URL ${item.url}`);
|
|
@@ -355,111 +442,135 @@ export class Downloader {
|
|
|
355
442
|
else {
|
|
356
443
|
res = await this.requestWithRetry(fetchImpl, item, headers, 0, expectedSize, signal, reportStage).catch(rethrowAsString);
|
|
357
444
|
}
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
445
|
+
if (signal.aborted) {
|
|
446
|
+
await res.body?.cancel().catch(() => { });
|
|
447
|
+
throw new Error(DOWNLOAD_CANCELLED);
|
|
448
|
+
}
|
|
449
|
+
let writer = await openWriteStream(tmpPath, shouldResume ? 'a' : 'w', disk).catch(async (e) => {
|
|
450
|
+
await res.body?.cancel().catch(() => { });
|
|
451
|
+
throw e;
|
|
361
452
|
});
|
|
362
|
-
const close = () => new Promise((ok, fail) => writer.end((e) => (e ? fail(disk(e)) : ok())));
|
|
363
453
|
let body = res.body ?? new ReadableStream({ start: (c) => c.close() });
|
|
364
454
|
let reader = body.getReader();
|
|
365
455
|
let delta = 0;
|
|
366
456
|
let retryCount = 0;
|
|
367
457
|
let sinceReset = 0;
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
if (
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
else if (value) {
|
|
380
|
-
if (signal.aborted) {
|
|
381
|
-
await close().catch(() => { });
|
|
382
|
-
this.deps.log('info', `Download cancelled: ${item.url}`);
|
|
383
|
-
throw new Error(DOWNLOAD_CANCELLED);
|
|
384
|
-
}
|
|
385
|
-
await write(value);
|
|
386
|
-
delta += value.byteLength;
|
|
387
|
-
totalTransferred += value.byteLength;
|
|
388
|
-
sinceReset += value.byteLength;
|
|
389
|
-
if (sinceReset >= RETRY_RESET_PROGRESS_BYTES) {
|
|
390
|
-
retryCount = 0;
|
|
391
|
-
sinceReset = 0;
|
|
458
|
+
try {
|
|
459
|
+
for (;;) {
|
|
460
|
+
let streamError;
|
|
461
|
+
try {
|
|
462
|
+
const { done, value } = await reader.read();
|
|
463
|
+
if (done) {
|
|
464
|
+
if (expectedSize > 0 && totalTransferred < expectedSize) {
|
|
465
|
+
streamError = `stream ended after ${totalTransferred} of ${expectedSize} bytes`;
|
|
466
|
+
}
|
|
467
|
+
else
|
|
468
|
+
break;
|
|
392
469
|
}
|
|
393
|
-
if (
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
470
|
+
else if (value) {
|
|
471
|
+
if (signal.aborted) {
|
|
472
|
+
await writer.close().catch(() => { });
|
|
473
|
+
this.deps.log('info', `Download cancelled: ${item.url}`);
|
|
474
|
+
throw new Error(DOWNLOAD_CANCELLED);
|
|
475
|
+
}
|
|
476
|
+
// Writes are awaited one at a time, so `totalTransferred` is where this chunk starts.
|
|
477
|
+
await writer.write(value, totalTransferred);
|
|
478
|
+
delta += value.byteLength;
|
|
479
|
+
totalTransferred += value.byteLength;
|
|
480
|
+
sinceReset += value.byteLength;
|
|
481
|
+
if (sinceReset >= RETRY_RESET_PROGRESS_BYTES) {
|
|
482
|
+
retryCount = 0;
|
|
483
|
+
sinceReset = 0;
|
|
484
|
+
}
|
|
485
|
+
if (delta >= PROGRESS_EMIT_INTERVAL_BYTES) {
|
|
486
|
+
progress.set(fileId, totalTransferred);
|
|
487
|
+
emitProgress();
|
|
488
|
+
delta = 0;
|
|
489
|
+
}
|
|
397
490
|
}
|
|
398
491
|
}
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
streamError = e.message;
|
|
406
|
-
}
|
|
407
|
-
if (streamError === undefined)
|
|
408
|
-
continue;
|
|
409
|
-
await close().catch((e) => {
|
|
410
|
-
throw new Error(`${e.message} (failed to flush partial download before retrying '${item.url}')`);
|
|
411
|
-
});
|
|
412
|
-
const durable = (await stat(tmpPath).catch((e) => {
|
|
413
|
-
throw disk(e);
|
|
414
|
-
})).size;
|
|
415
|
-
if (durable !== totalTransferred) {
|
|
416
|
-
throw new Error(`Partial download size mismatch for '${item.url}': tracked ${totalTransferred} bytes but persisted ${durable} bytes`);
|
|
417
|
-
}
|
|
418
|
-
for (;;) {
|
|
419
|
-
if (retryCount >= MAX_STREAM_RETRIES) {
|
|
420
|
-
throw new Error(`Download failed after ${MAX_STREAM_RETRIES} retries at byte ${durable}: ${streamError}`);
|
|
492
|
+
catch (e) {
|
|
493
|
+
if (e.message === DOWNLOAD_CANCELLED || e.message.startsWith('Error: ['))
|
|
494
|
+
throw e;
|
|
495
|
+
if (signal.aborted)
|
|
496
|
+
throw new Error(DOWNLOAD_CANCELLED);
|
|
497
|
+
streamError = e.message;
|
|
421
498
|
}
|
|
422
|
-
if (
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
499
|
+
if (streamError === undefined)
|
|
500
|
+
continue;
|
|
501
|
+
await writer.close().catch((e) => {
|
|
502
|
+
throw new Error(`${e.message} (failed to flush partial download before retrying '${item.url}')`);
|
|
503
|
+
});
|
|
504
|
+
const durable = (await stat(tmpPath).catch((e) => {
|
|
505
|
+
throw disk(e);
|
|
506
|
+
})).size;
|
|
507
|
+
if (durable !== totalTransferred) {
|
|
508
|
+
throw new Error(`Partial download size mismatch for '${item.url}': tracked ${totalTransferred} bytes but persisted ${durable} bytes`);
|
|
431
509
|
}
|
|
432
|
-
|
|
433
|
-
if (
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
510
|
+
for (;;) {
|
|
511
|
+
if (retryCount >= MAX_STREAM_RETRIES) {
|
|
512
|
+
throw new Error(`Download failed after ${MAX_STREAM_RETRIES} retries at byte ${durable}: ${streamError}`, { cause: streamError });
|
|
513
|
+
}
|
|
514
|
+
if (signal.aborted)
|
|
515
|
+
throw new Error(DOWNLOAD_CANCELLED);
|
|
516
|
+
this.deps.log('warn', `Stream error at byte ${durable} for '${item.url}': ${streamError}. Retry ${retryCount + 1}/${MAX_STREAM_RETRIES}`);
|
|
517
|
+
await this.deps.sleep(retryDelayMs(retryCount, this.deps.retryBaseMs), signal);
|
|
518
|
+
retryCount++;
|
|
519
|
+
try {
|
|
520
|
+
res = await this.request(fetchImpl, item, headers, durable, expectedSize, signal);
|
|
521
|
+
if (signal.aborted) {
|
|
522
|
+
await res.body?.cancel().catch(() => { });
|
|
523
|
+
throw new Error(DOWNLOAD_CANCELLED);
|
|
443
524
|
}
|
|
444
|
-
catch (
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
525
|
+
writer = await openWriteStream(tmpPath, 'a', disk).catch(async (e) => {
|
|
526
|
+
await res.body?.cancel().catch(() => { });
|
|
527
|
+
throw e;
|
|
528
|
+
});
|
|
529
|
+
break;
|
|
530
|
+
}
|
|
531
|
+
catch (e) {
|
|
532
|
+
if (e instanceof DownloadRequestError && e.kind === 'restart') {
|
|
533
|
+
try {
|
|
534
|
+
res = await this.request(fetchImpl, item, headers, 0, expectedSize, signal);
|
|
535
|
+
if (signal.aborted) {
|
|
536
|
+
await res.body?.cancel().catch(() => { });
|
|
537
|
+
throw new Error(DOWNLOAD_CANCELLED);
|
|
538
|
+
}
|
|
539
|
+
writer = await openWriteStream(tmpPath, 'w', disk).catch(async (e2) => {
|
|
540
|
+
await res.body?.cancel().catch(() => { });
|
|
541
|
+
throw e2;
|
|
542
|
+
});
|
|
543
|
+
progress.set(fileId, 0);
|
|
544
|
+
totalTransferred = 0;
|
|
545
|
+
delta = 0;
|
|
546
|
+
sinceReset = 0;
|
|
547
|
+
this.deps.log('warn', `Server cannot resume '${item.url}' (${e.message}); restarted from byte 0`);
|
|
548
|
+
break;
|
|
549
|
+
}
|
|
550
|
+
catch (e2) {
|
|
551
|
+
if (e2 instanceof DownloadRequestError && e2.kind === 'retryable') {
|
|
552
|
+
this.deps.log('warn', `Full-download reconnect for '${item.url}' failed: ${e2.message}`);
|
|
553
|
+
continue;
|
|
554
|
+
}
|
|
555
|
+
throw rethrowAsString(e2);
|
|
448
556
|
}
|
|
449
|
-
throw rethrowAsString(e2);
|
|
450
557
|
}
|
|
558
|
+
if (e instanceof DownloadRequestError && e.kind === 'retryable') {
|
|
559
|
+
this.deps.log('warn', `Range reconnect at byte ${durable} for '${item.url}' failed: ${e.message}`);
|
|
560
|
+
continue;
|
|
561
|
+
}
|
|
562
|
+
throw rethrowAsString(e);
|
|
451
563
|
}
|
|
452
|
-
if (e instanceof DownloadRequestError && e.kind === 'retryable') {
|
|
453
|
-
this.deps.log('warn', `Range reconnect at byte ${durable} for '${item.url}' failed: ${e.message}`);
|
|
454
|
-
continue;
|
|
455
|
-
}
|
|
456
|
-
throw rethrowAsString(e);
|
|
457
564
|
}
|
|
565
|
+
body = res.body ?? new ReadableStream({ start: (c) => c.close() });
|
|
566
|
+
reader = body.getReader();
|
|
458
567
|
}
|
|
459
|
-
|
|
460
|
-
|
|
568
|
+
await writer.close();
|
|
569
|
+
}
|
|
570
|
+
finally {
|
|
571
|
+
await writer.close().catch(() => { });
|
|
572
|
+
await reader.cancel().catch(() => { });
|
|
461
573
|
}
|
|
462
|
-
await close();
|
|
463
574
|
const persisted = (await stat(tmpPath).catch((e) => {
|
|
464
575
|
throw disk(e);
|
|
465
576
|
})).size;
|
|
@@ -484,7 +595,7 @@ export class Downloader {
|
|
|
484
595
|
/** Request errors reach the caller as plain `Error`s with the Rust message text. */
|
|
485
596
|
function rethrowAsString(e) {
|
|
486
597
|
if (e instanceof DownloadRequestError)
|
|
487
|
-
throw new Error(e.message);
|
|
598
|
+
throw new Error(e.message, { cause: e });
|
|
488
599
|
throw e;
|
|
489
600
|
}
|
|
490
601
|
//# sourceMappingURL=downloader.js.map
|