@camstack/addon-pipeline 1.2.52 → 1.2.53
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/{addon-utils-DveoBR6G.js → addon-utils-CQs-AjTJ.js} +177 -177
- package/dist/{addon-utils-QuxtOdK1.mjs → addon-utils-CZ2xo67g.mjs} +177 -177
- package/dist/audio-analyzer/index.js +2 -2
- package/dist/audio-analyzer/index.mjs +2 -2
- package/dist/detection-pipeline/index.js +3 -3
- package/dist/detection-pipeline/index.mjs +3 -3
- package/dist/{dist-gB3o0cyM.mjs → dist-B55xTTsS.mjs} +368 -5
- package/dist/{dist-CzFJeiG1.js → dist-D8TX_P_A.js} +368 -5
- package/dist/{event-loop-stall-monitor-DSPDQYjc.js → event-loop-stall-monitor-Bs6d-u_F.js} +1 -1
- package/dist/{event-loop-stall-monitor-PxIaVeyh.mjs → event-loop-stall-monitor-Cq_KOlfb.mjs} +1 -1
- package/dist/motion-wasm/index.js +1 -1
- package/dist/motion-wasm/index.mjs +1 -1
- package/dist/pipeline-runner/index.js +75 -25
- package/dist/pipeline-runner/index.mjs +75 -25
- package/dist/recorder/index.js +2 -2
- package/dist/recorder/index.mjs +2 -2
- package/dist/session-decode/decode-worker-child.js +6 -2
- package/dist/session-decode/decode-worker-child.mjs +6 -2
- package/dist/stream-broker/_stub.js +2 -2
- package/dist/stream-broker/{_virtual_mf-localSharedImportMap___mfe_internal__addon_stream_broker_widgets-DAeBhR8B.mjs → _virtual_mf-localSharedImportMap___mfe_internal__addon_stream_broker_widgets-C-9q6y1s.mjs} +3 -3
- package/dist/stream-broker/_virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-CAmiVOsA.mjs +26 -0
- package/dist/stream-broker/_virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_ui_mf_2_library__loadShare__.js-CaGsMvou.mjs +26 -0
- package/dist/stream-broker/{hostInit-DniAXKLy.mjs → hostInit-DiXYwnXH.mjs} +3 -3
- package/dist/stream-broker/index.js +2 -2
- package/dist/stream-broker/index.mjs +2 -2
- package/dist/stream-broker/remoteEntry.js +1 -1
- package/dist/{worker-protocol-BhhX7J4-.mjs → worker-protocol-Bol291_n.mjs} +1 -1
- package/dist/{worker-protocol-BQlELGzv.js → worker-protocol-C2uctCrd.js} +1 -1
- package/embed-dist/assets/{MaskShapeCanvas-DI4BY7W2-B1gpA9sI.js → MaskShapeCanvas-DI4BY7W2-CXHeTkIT.js} +1 -1
- package/embed-dist/assets/{MotionZonesSettings-NcxxQN8r-DV6vvNDq.js → MotionZonesSettings-NcxxQN8r-De5VKf09.js} +1 -1
- package/embed-dist/assets/{PrivacyMaskSettings-APgPLF7p-BmUdRoZ9.js → PrivacyMaskSettings-APgPLF7p-Z7dsjOG5.js} +1 -1
- package/embed-dist/assets/{index-DsGzhGCW.js → index-NJB31mpg.js} +12 -12
- package/embed-dist/index.html +1 -1
- package/package.json +1 -1
- package/dist/stream-broker/_virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-Bl9zivOk.mjs +0 -26
- package/dist/stream-broker/_virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_ui_mf_2_library__loadShare__.js-Czrsozsg.mjs +0 -26
|
@@ -6,7 +6,183 @@ let node_path = require("node:path");
|
|
|
6
6
|
node_path = require_chunk.__toESM(node_path, 1);
|
|
7
7
|
let node_util = require("node:util");
|
|
8
8
|
let node_zlib = require("node:zlib");
|
|
9
|
-
//#region ../system/dist/
|
|
9
|
+
//#region ../system/dist/file-data-plane-CuE_hBli.mjs
|
|
10
|
+
function isNonEmptyFile(filePath) {
|
|
11
|
+
return node_fs.existsSync(filePath) && node_fs.statSync(filePath).size > 0;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Sibling files of a single-file (non-directory) format — extra files the
|
|
15
|
+
* format needs, fetched from the same remote directory as `url` and stored
|
|
16
|
+
* flat alongside the main file in `modelsDir`. Catalog-declared via
|
|
17
|
+
* `formatEntry.files`, e.g. OpenVINO IR lists its `.bin` weights next to the
|
|
18
|
+
* `.xml`. The downloader stays format-agnostic; the convention lives in the
|
|
19
|
+
* catalog data (like `MLPACKAGE_FILES` for the directory case).
|
|
20
|
+
*/
|
|
21
|
+
function siblingFilesFor(formatEntry) {
|
|
22
|
+
return formatEntry.isDirectory ? [] : formatEntry.files ?? [];
|
|
23
|
+
}
|
|
24
|
+
/** Resolve a sibling's remote URL relative to the main file's directory. */
|
|
25
|
+
function siblingUrl(mainUrl, sibling) {
|
|
26
|
+
return mainUrl.replace(/[^/]+$/, sibling);
|
|
27
|
+
}
|
|
28
|
+
/** Build fetch headers, including HF auth token for huggingface.co URLs */
|
|
29
|
+
function buildHeaders(url) {
|
|
30
|
+
const headers = { "User-Agent": "CamStack/1.0" };
|
|
31
|
+
const hfToken = process.env["HF_TOKEN"] ?? process.env["HUGGING_FACE_HUB_TOKEN"];
|
|
32
|
+
if (hfToken && url.includes("huggingface.co")) headers["Authorization"] = `Bearer ${hfToken}`;
|
|
33
|
+
return headers;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Download a single file from a URL to a destination path.
|
|
37
|
+
* Uses native fetch() (Node 22+) which handles redirects natively.
|
|
38
|
+
* Streams to disk with optional progress callback.
|
|
39
|
+
* Returns the destination path. Skips download if file already exists.
|
|
40
|
+
*/
|
|
41
|
+
async function downloadFile(url, destPath, onProgress) {
|
|
42
|
+
if (node_fs.existsSync(destPath)) return destPath;
|
|
43
|
+
node_fs.mkdirSync(node_path.dirname(destPath), { recursive: true });
|
|
44
|
+
const tmpPath = destPath + ".downloading";
|
|
45
|
+
try {
|
|
46
|
+
const response = await fetch(url, {
|
|
47
|
+
redirect: "follow",
|
|
48
|
+
headers: buildHeaders(url)
|
|
49
|
+
});
|
|
50
|
+
if (!response.ok) throw new Error(`HTTP ${response.status} downloading ${url}`);
|
|
51
|
+
if (!response.body) throw new Error(`No response body from ${url}`);
|
|
52
|
+
const total = parseInt(response.headers.get("content-length") ?? "0", 10);
|
|
53
|
+
let downloaded = 0;
|
|
54
|
+
const fileStream = node_fs.createWriteStream(tmpPath);
|
|
55
|
+
const reader = response.body.getReader();
|
|
56
|
+
try {
|
|
57
|
+
for (;;) {
|
|
58
|
+
const { done, value } = await reader.read();
|
|
59
|
+
if (done || !value) break;
|
|
60
|
+
fileStream.write(value);
|
|
61
|
+
downloaded += value.length;
|
|
62
|
+
onProgress?.(downloaded, total);
|
|
63
|
+
}
|
|
64
|
+
} finally {
|
|
65
|
+
fileStream.end();
|
|
66
|
+
await new Promise((resolve, reject) => {
|
|
67
|
+
fileStream.on("finish", resolve);
|
|
68
|
+
fileStream.on("error", reject);
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
node_fs.renameSync(tmpPath, destPath);
|
|
72
|
+
return destPath;
|
|
73
|
+
} catch (err) {
|
|
74
|
+
try {
|
|
75
|
+
node_fs.unlinkSync(tmpPath);
|
|
76
|
+
} catch {}
|
|
77
|
+
throw err;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Download every file in a HuggingFace directory bundle (e.g.,
|
|
82
|
+
* `.mlpackage` / OpenVINO IR pair) atomically. `knownFiles` lists the
|
|
83
|
+
* relative paths inside the directory; the function fetches each from
|
|
84
|
+
* `${url}/${file}` and renames the staging directory only on full
|
|
85
|
+
* success. Mirrors `ModelDownloadService.downloadDirectory` but
|
|
86
|
+
* exposed as a standalone for catalog-less callers.
|
|
87
|
+
*/
|
|
88
|
+
async function downloadDirectory(url, destDir, knownFiles, onProgress) {
|
|
89
|
+
const match = url.match(/huggingface\.co\/([^/]+\/[^/]+)\/resolve\/main\/(.+)/);
|
|
90
|
+
if (!match) throw new Error(`Cannot parse HuggingFace URL: ${url}`);
|
|
91
|
+
const [, repo, dirPath] = match;
|
|
92
|
+
const files = (knownFiles ?? []).map((f) => ({
|
|
93
|
+
relativePath: f,
|
|
94
|
+
fileUrl: `https://huggingface.co/${repo}/resolve/main/${dirPath}/${f}`
|
|
95
|
+
}));
|
|
96
|
+
if (files.length === 0) throw new Error(`Directory bundle requires explicit \`files\` list (got none for ${url})`);
|
|
97
|
+
const tmpDir = destDir + ".downloading";
|
|
98
|
+
node_fs.rmSync(tmpDir, {
|
|
99
|
+
recursive: true,
|
|
100
|
+
force: true
|
|
101
|
+
});
|
|
102
|
+
node_fs.mkdirSync(tmpDir, { recursive: true });
|
|
103
|
+
let totalDownloaded = 0;
|
|
104
|
+
try {
|
|
105
|
+
for (const file of files) {
|
|
106
|
+
const destPath = node_path.join(tmpDir, file.relativePath);
|
|
107
|
+
node_fs.mkdirSync(node_path.dirname(destPath), { recursive: true });
|
|
108
|
+
await downloadFile(file.fileUrl, destPath, (downloaded, _total) => {
|
|
109
|
+
onProgress?.(totalDownloaded + downloaded, void 0);
|
|
110
|
+
});
|
|
111
|
+
totalDownloaded += node_fs.statSync(destPath).size;
|
|
112
|
+
}
|
|
113
|
+
node_fs.rmSync(destDir, {
|
|
114
|
+
recursive: true,
|
|
115
|
+
force: true
|
|
116
|
+
});
|
|
117
|
+
node_fs.renameSync(tmpDir, destDir);
|
|
118
|
+
} catch (err) {
|
|
119
|
+
node_fs.rmSync(tmpDir, {
|
|
120
|
+
recursive: true,
|
|
121
|
+
force: true
|
|
122
|
+
});
|
|
123
|
+
throw err;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Resolve a `ModelCatalogEntry` against `modelsDir`: download model file
|
|
128
|
+
* (or directory bundle) + extra files (labels JSON, charset dict, …),
|
|
129
|
+
* skip if already on disk. Returns the local model path.
|
|
130
|
+
*/
|
|
131
|
+
async function ensureModel(modelsDir, entry, format, onProgress) {
|
|
132
|
+
const formatEntry = entry.formats[format];
|
|
133
|
+
if (!formatEntry) throw new Error(`Model "${entry.id}" has no ${format} format. Available: ${Object.keys(entry.formats).join(", ")}`);
|
|
134
|
+
if (entry.extraFiles) for (const extra of entry.extraFiles) await downloadFile(extra.url, node_path.join(modelsDir, extra.filename));
|
|
135
|
+
const filename = formatEntry.url.split("/").pop() ?? `${entry.id}.${format}`;
|
|
136
|
+
const modelPath = node_path.join(modelsDir, filename);
|
|
137
|
+
const siblings = siblingFilesFor(formatEntry);
|
|
138
|
+
if (node_fs.existsSync(modelPath)) if (formatEntry.isDirectory && !node_fs.existsSync(node_path.join(modelPath, "Manifest.json"))) node_fs.rmSync(modelPath, {
|
|
139
|
+
recursive: true,
|
|
140
|
+
force: true
|
|
141
|
+
});
|
|
142
|
+
else if (siblings.some((f) => !isNonEmptyFile(node_path.join(modelsDir, f)))) {} else return modelPath;
|
|
143
|
+
node_fs.mkdirSync(modelsDir, { recursive: true });
|
|
144
|
+
if (formatEntry.isDirectory) await downloadDirectory(formatEntry.url, modelPath, formatEntry.files, onProgress);
|
|
145
|
+
else {
|
|
146
|
+
await downloadFile(formatEntry.url, modelPath, (downloaded, total) => onProgress?.(downloaded, total === 0 ? void 0 : total));
|
|
147
|
+
for (const sibling of siblings) await downloadFile(siblingUrl(formatEntry.url, sibling), node_path.join(modelsDir, sibling));
|
|
148
|
+
}
|
|
149
|
+
return modelPath;
|
|
150
|
+
}
|
|
151
|
+
/** Compute the on-disk path for a given model + format, even when not yet downloaded. */
|
|
152
|
+
function getModelFilePath(modelsDir, entry, format) {
|
|
153
|
+
const formatEntry = entry.formats[format];
|
|
154
|
+
if (!formatEntry) return null;
|
|
155
|
+
const filename = formatEntry.url.split("/").pop() ?? `${entry.id}.${format}`;
|
|
156
|
+
return node_path.join(modelsDir, filename);
|
|
157
|
+
}
|
|
158
|
+
/** True iff the model file (or `Manifest.json` for directory bundles) exists and is non-empty. */
|
|
159
|
+
function isModelDownloaded(modelsDir, entry, format) {
|
|
160
|
+
const formatEntry = entry.formats[format];
|
|
161
|
+
if (!formatEntry) return false;
|
|
162
|
+
const modelPath = getModelFilePath(modelsDir, entry, format);
|
|
163
|
+
if (!modelPath || !node_fs.existsSync(modelPath)) return false;
|
|
164
|
+
if (formatEntry.isDirectory) return node_fs.existsSync(node_path.join(modelPath, "Manifest.json"));
|
|
165
|
+
if (node_fs.statSync(modelPath).size <= 0) return false;
|
|
166
|
+
return siblingFilesFor(formatEntry).every((f) => isNonEmptyFile(node_path.join(modelsDir, f)));
|
|
167
|
+
}
|
|
168
|
+
/** Remove the on-disk model file/directory. Returns true if something was deleted. */
|
|
169
|
+
function deleteModelFromDisk(modelsDir, entry, format) {
|
|
170
|
+
const modelPath = getModelFilePath(modelsDir, entry, format);
|
|
171
|
+
if (!modelPath || !node_fs.existsSync(modelPath)) return false;
|
|
172
|
+
const formatEntry = entry.formats[format];
|
|
173
|
+
if (formatEntry?.isDirectory) node_fs.rmSync(modelPath, {
|
|
174
|
+
recursive: true,
|
|
175
|
+
force: true
|
|
176
|
+
});
|
|
177
|
+
else {
|
|
178
|
+
node_fs.unlinkSync(modelPath);
|
|
179
|
+
if (formatEntry) for (const sibling of siblingFilesFor(formatEntry)) {
|
|
180
|
+
const sibPath = node_path.join(modelsDir, sibling);
|
|
181
|
+
if (node_fs.existsSync(sibPath)) node_fs.unlinkSync(sibPath);
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
return true;
|
|
185
|
+
}
|
|
10
186
|
/**
|
|
11
187
|
* Map a rel path to one candidate absolute path PER root, keeping only roots the
|
|
12
188
|
* path stays within (traversal guard). The handler serves the first candidate
|
|
@@ -368,182 +544,6 @@ function createFileDataPlaneHandler(opts) {
|
|
|
368
544
|
(0, node_fs.createReadStream)(absPath).pipe(res);
|
|
369
545
|
};
|
|
370
546
|
}
|
|
371
|
-
function isNonEmptyFile(filePath) {
|
|
372
|
-
return node_fs.existsSync(filePath) && node_fs.statSync(filePath).size > 0;
|
|
373
|
-
}
|
|
374
|
-
/**
|
|
375
|
-
* Sibling files of a single-file (non-directory) format — extra files the
|
|
376
|
-
* format needs, fetched from the same remote directory as `url` and stored
|
|
377
|
-
* flat alongside the main file in `modelsDir`. Catalog-declared via
|
|
378
|
-
* `formatEntry.files`, e.g. OpenVINO IR lists its `.bin` weights next to the
|
|
379
|
-
* `.xml`. The downloader stays format-agnostic; the convention lives in the
|
|
380
|
-
* catalog data (like `MLPACKAGE_FILES` for the directory case).
|
|
381
|
-
*/
|
|
382
|
-
function siblingFilesFor(formatEntry) {
|
|
383
|
-
return formatEntry.isDirectory ? [] : formatEntry.files ?? [];
|
|
384
|
-
}
|
|
385
|
-
/** Resolve a sibling's remote URL relative to the main file's directory. */
|
|
386
|
-
function siblingUrl(mainUrl, sibling) {
|
|
387
|
-
return mainUrl.replace(/[^/]+$/, sibling);
|
|
388
|
-
}
|
|
389
|
-
/** Build fetch headers, including HF auth token for huggingface.co URLs */
|
|
390
|
-
function buildHeaders(url) {
|
|
391
|
-
const headers = { "User-Agent": "CamStack/1.0" };
|
|
392
|
-
const hfToken = process.env["HF_TOKEN"] ?? process.env["HUGGING_FACE_HUB_TOKEN"];
|
|
393
|
-
if (hfToken && url.includes("huggingface.co")) headers["Authorization"] = `Bearer ${hfToken}`;
|
|
394
|
-
return headers;
|
|
395
|
-
}
|
|
396
|
-
/**
|
|
397
|
-
* Download a single file from a URL to a destination path.
|
|
398
|
-
* Uses native fetch() (Node 22+) which handles redirects natively.
|
|
399
|
-
* Streams to disk with optional progress callback.
|
|
400
|
-
* Returns the destination path. Skips download if file already exists.
|
|
401
|
-
*/
|
|
402
|
-
async function downloadFile(url, destPath, onProgress) {
|
|
403
|
-
if (node_fs.existsSync(destPath)) return destPath;
|
|
404
|
-
node_fs.mkdirSync(node_path.dirname(destPath), { recursive: true });
|
|
405
|
-
const tmpPath = destPath + ".downloading";
|
|
406
|
-
try {
|
|
407
|
-
const response = await fetch(url, {
|
|
408
|
-
redirect: "follow",
|
|
409
|
-
headers: buildHeaders(url)
|
|
410
|
-
});
|
|
411
|
-
if (!response.ok) throw new Error(`HTTP ${response.status} downloading ${url}`);
|
|
412
|
-
if (!response.body) throw new Error(`No response body from ${url}`);
|
|
413
|
-
const total = parseInt(response.headers.get("content-length") ?? "0", 10);
|
|
414
|
-
let downloaded = 0;
|
|
415
|
-
const fileStream = node_fs.createWriteStream(tmpPath);
|
|
416
|
-
const reader = response.body.getReader();
|
|
417
|
-
try {
|
|
418
|
-
for (;;) {
|
|
419
|
-
const { done, value } = await reader.read();
|
|
420
|
-
if (done || !value) break;
|
|
421
|
-
fileStream.write(value);
|
|
422
|
-
downloaded += value.length;
|
|
423
|
-
onProgress?.(downloaded, total);
|
|
424
|
-
}
|
|
425
|
-
} finally {
|
|
426
|
-
fileStream.end();
|
|
427
|
-
await new Promise((resolve, reject) => {
|
|
428
|
-
fileStream.on("finish", resolve);
|
|
429
|
-
fileStream.on("error", reject);
|
|
430
|
-
});
|
|
431
|
-
}
|
|
432
|
-
node_fs.renameSync(tmpPath, destPath);
|
|
433
|
-
return destPath;
|
|
434
|
-
} catch (err) {
|
|
435
|
-
try {
|
|
436
|
-
node_fs.unlinkSync(tmpPath);
|
|
437
|
-
} catch {}
|
|
438
|
-
throw err;
|
|
439
|
-
}
|
|
440
|
-
}
|
|
441
|
-
/**
|
|
442
|
-
* Download every file in a HuggingFace directory bundle (e.g.,
|
|
443
|
-
* `.mlpackage` / OpenVINO IR pair) atomically. `knownFiles` lists the
|
|
444
|
-
* relative paths inside the directory; the function fetches each from
|
|
445
|
-
* `${url}/${file}` and renames the staging directory only on full
|
|
446
|
-
* success. Mirrors `ModelDownloadService.downloadDirectory` but
|
|
447
|
-
* exposed as a standalone for catalog-less callers.
|
|
448
|
-
*/
|
|
449
|
-
async function downloadDirectory(url, destDir, knownFiles, onProgress) {
|
|
450
|
-
const match = url.match(/huggingface\.co\/([^/]+\/[^/]+)\/resolve\/main\/(.+)/);
|
|
451
|
-
if (!match) throw new Error(`Cannot parse HuggingFace URL: ${url}`);
|
|
452
|
-
const [, repo, dirPath] = match;
|
|
453
|
-
const files = (knownFiles ?? []).map((f) => ({
|
|
454
|
-
relativePath: f,
|
|
455
|
-
fileUrl: `https://huggingface.co/${repo}/resolve/main/${dirPath}/${f}`
|
|
456
|
-
}));
|
|
457
|
-
if (files.length === 0) throw new Error(`Directory bundle requires explicit \`files\` list (got none for ${url})`);
|
|
458
|
-
const tmpDir = destDir + ".downloading";
|
|
459
|
-
node_fs.rmSync(tmpDir, {
|
|
460
|
-
recursive: true,
|
|
461
|
-
force: true
|
|
462
|
-
});
|
|
463
|
-
node_fs.mkdirSync(tmpDir, { recursive: true });
|
|
464
|
-
let totalDownloaded = 0;
|
|
465
|
-
try {
|
|
466
|
-
for (const file of files) {
|
|
467
|
-
const destPath = node_path.join(tmpDir, file.relativePath);
|
|
468
|
-
node_fs.mkdirSync(node_path.dirname(destPath), { recursive: true });
|
|
469
|
-
await downloadFile(file.fileUrl, destPath, (downloaded, _total) => {
|
|
470
|
-
onProgress?.(totalDownloaded + downloaded, void 0);
|
|
471
|
-
});
|
|
472
|
-
totalDownloaded += node_fs.statSync(destPath).size;
|
|
473
|
-
}
|
|
474
|
-
node_fs.rmSync(destDir, {
|
|
475
|
-
recursive: true,
|
|
476
|
-
force: true
|
|
477
|
-
});
|
|
478
|
-
node_fs.renameSync(tmpDir, destDir);
|
|
479
|
-
} catch (err) {
|
|
480
|
-
node_fs.rmSync(tmpDir, {
|
|
481
|
-
recursive: true,
|
|
482
|
-
force: true
|
|
483
|
-
});
|
|
484
|
-
throw err;
|
|
485
|
-
}
|
|
486
|
-
}
|
|
487
|
-
/**
|
|
488
|
-
* Resolve a `ModelCatalogEntry` against `modelsDir`: download model file
|
|
489
|
-
* (or directory bundle) + extra files (labels JSON, charset dict, …),
|
|
490
|
-
* skip if already on disk. Returns the local model path.
|
|
491
|
-
*/
|
|
492
|
-
async function ensureModel(modelsDir, entry, format, onProgress) {
|
|
493
|
-
const formatEntry = entry.formats[format];
|
|
494
|
-
if (!formatEntry) throw new Error(`Model "${entry.id}" has no ${format} format. Available: ${Object.keys(entry.formats).join(", ")}`);
|
|
495
|
-
if (entry.extraFiles) for (const extra of entry.extraFiles) await downloadFile(extra.url, node_path.join(modelsDir, extra.filename));
|
|
496
|
-
const filename = formatEntry.url.split("/").pop() ?? `${entry.id}.${format}`;
|
|
497
|
-
const modelPath = node_path.join(modelsDir, filename);
|
|
498
|
-
const siblings = siblingFilesFor(formatEntry);
|
|
499
|
-
if (node_fs.existsSync(modelPath)) if (formatEntry.isDirectory && !node_fs.existsSync(node_path.join(modelPath, "Manifest.json"))) node_fs.rmSync(modelPath, {
|
|
500
|
-
recursive: true,
|
|
501
|
-
force: true
|
|
502
|
-
});
|
|
503
|
-
else if (siblings.some((f) => !isNonEmptyFile(node_path.join(modelsDir, f)))) {} else return modelPath;
|
|
504
|
-
node_fs.mkdirSync(modelsDir, { recursive: true });
|
|
505
|
-
if (formatEntry.isDirectory) await downloadDirectory(formatEntry.url, modelPath, formatEntry.files, onProgress);
|
|
506
|
-
else {
|
|
507
|
-
await downloadFile(formatEntry.url, modelPath, (downloaded, total) => onProgress?.(downloaded, total === 0 ? void 0 : total));
|
|
508
|
-
for (const sibling of siblings) await downloadFile(siblingUrl(formatEntry.url, sibling), node_path.join(modelsDir, sibling));
|
|
509
|
-
}
|
|
510
|
-
return modelPath;
|
|
511
|
-
}
|
|
512
|
-
/** Compute the on-disk path for a given model + format, even when not yet downloaded. */
|
|
513
|
-
function getModelFilePath(modelsDir, entry, format) {
|
|
514
|
-
const formatEntry = entry.formats[format];
|
|
515
|
-
if (!formatEntry) return null;
|
|
516
|
-
const filename = formatEntry.url.split("/").pop() ?? `${entry.id}.${format}`;
|
|
517
|
-
return node_path.join(modelsDir, filename);
|
|
518
|
-
}
|
|
519
|
-
/** True iff the model file (or `Manifest.json` for directory bundles) exists and is non-empty. */
|
|
520
|
-
function isModelDownloaded(modelsDir, entry, format) {
|
|
521
|
-
const formatEntry = entry.formats[format];
|
|
522
|
-
if (!formatEntry) return false;
|
|
523
|
-
const modelPath = getModelFilePath(modelsDir, entry, format);
|
|
524
|
-
if (!modelPath || !node_fs.existsSync(modelPath)) return false;
|
|
525
|
-
if (formatEntry.isDirectory) return node_fs.existsSync(node_path.join(modelPath, "Manifest.json"));
|
|
526
|
-
if (node_fs.statSync(modelPath).size <= 0) return false;
|
|
527
|
-
return siblingFilesFor(formatEntry).every((f) => isNonEmptyFile(node_path.join(modelsDir, f)));
|
|
528
|
-
}
|
|
529
|
-
/** Remove the on-disk model file/directory. Returns true if something was deleted. */
|
|
530
|
-
function deleteModelFromDisk(modelsDir, entry, format) {
|
|
531
|
-
const modelPath = getModelFilePath(modelsDir, entry, format);
|
|
532
|
-
if (!modelPath || !node_fs.existsSync(modelPath)) return false;
|
|
533
|
-
const formatEntry = entry.formats[format];
|
|
534
|
-
if (formatEntry?.isDirectory) node_fs.rmSync(modelPath, {
|
|
535
|
-
recursive: true,
|
|
536
|
-
force: true
|
|
537
|
-
});
|
|
538
|
-
else {
|
|
539
|
-
node_fs.unlinkSync(modelPath);
|
|
540
|
-
if (formatEntry) for (const sibling of siblingFilesFor(formatEntry)) {
|
|
541
|
-
const sibPath = node_path.join(modelsDir, sibling);
|
|
542
|
-
if (node_fs.existsSync(sibPath)) node_fs.unlinkSync(sibPath);
|
|
543
|
-
}
|
|
544
|
-
}
|
|
545
|
-
return true;
|
|
546
|
-
}
|
|
547
547
|
//#endregion
|
|
548
548
|
Object.defineProperty(exports, "contentTypeFor", {
|
|
549
549
|
enumerable: true,
|