@camstack/system 1.0.8 → 1.1.1
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-runner.js +1 -1
- package/dist/addon-runner.mjs +1 -1
- package/dist/addon-utils.d.ts +1 -1
- package/dist/addon-utils.js +3 -1
- package/dist/addon-utils.mjs +2 -2
- package/dist/download/model-downloader.d.ts +25 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +74 -6
- package/dist/index.mjs +73 -7
- package/dist/kernel/addon-installer.d.ts +20 -0
- package/dist/kernel/index.d.ts +1 -0
- package/dist/kernel/moleculer/addon-deploy-source.d.ts +16 -0
- package/dist/kernel/moleculer/trpc-links.d.ts +11 -0
- package/dist/kernel/transport/cap-route-resolver.d.ts +15 -0
- package/dist/{manifest-python-deps-BcrTzHH_.mjs → manifest-python-deps-8Wvwz-d1.mjs} +865 -837
- package/dist/{manifest-python-deps-BWURo7dc.js → manifest-python-deps-RihGbmpb.js} +864 -836
- package/dist/{model-download-service-C7AjBsX9.mjs → model-download-service-C-IHWnXx.mjs} +69 -14
- package/dist/{model-download-service-JtVQtbb6.js → model-download-service-D-Umz4-L.js} +74 -13
- package/package.json +1 -1
|
@@ -300,6 +300,42 @@ function createFileDataPlaneHandler(opts) {
|
|
|
300
300
|
}
|
|
301
301
|
//#endregion
|
|
302
302
|
//#region src/download/model-downloader.ts
|
|
303
|
+
function isNonEmptyFile(filePath) {
|
|
304
|
+
return fs.existsSync(filePath) && fs.statSync(filePath).size > 0;
|
|
305
|
+
}
|
|
306
|
+
/**
|
|
307
|
+
* Sibling files of a single-file (non-directory) format — extra files the
|
|
308
|
+
* format needs, fetched from the same remote directory as `url` and stored
|
|
309
|
+
* flat alongside the main file in `modelsDir`. Catalog-declared via
|
|
310
|
+
* `formatEntry.files`, e.g. OpenVINO IR lists its `.bin` weights next to the
|
|
311
|
+
* `.xml`. The downloader stays format-agnostic; the convention lives in the
|
|
312
|
+
* catalog data (like `MLPACKAGE_FILES` for the directory case).
|
|
313
|
+
*/
|
|
314
|
+
function siblingFilesFor(formatEntry) {
|
|
315
|
+
return formatEntry.isDirectory ? [] : formatEntry.files ?? [];
|
|
316
|
+
}
|
|
317
|
+
/** Resolve a sibling's remote URL relative to the main file's directory. */
|
|
318
|
+
function siblingUrl(mainUrl, sibling) {
|
|
319
|
+
return mainUrl.replace(/[^/]+$/, sibling);
|
|
320
|
+
}
|
|
321
|
+
/**
|
|
322
|
+
* The relative filenames a model format occupies under `modelsDir` — the main
|
|
323
|
+
* file (URL basename, or `${id}.${format}` fallback), its declared siblings
|
|
324
|
+
* (e.g. the OpenVINO `.bin` next to the `.xml`), and any `extraFiles`. For a
|
|
325
|
+
* directory bundle the single entry is the bundle dir itself (tar/extract
|
|
326
|
+
* recurse into it).
|
|
327
|
+
*
|
|
328
|
+
* Used by model distribution (P2): the hub tars exactly these names from its
|
|
329
|
+
* `modelsDir` and the agent untars them into its own `modelsDir`, so both ends
|
|
330
|
+
* agree on the on-disk layout without re-deriving it.
|
|
331
|
+
*/
|
|
332
|
+
function collectModelFiles(entry, format) {
|
|
333
|
+
const formatEntry = entry.formats[format];
|
|
334
|
+
if (!formatEntry) return [];
|
|
335
|
+
const names = [formatEntry.url.split("/").pop() ?? `${entry.id}.${format}`, ...siblingFilesFor(formatEntry)];
|
|
336
|
+
for (const extra of entry.extraFiles ?? []) names.push(extra.filename);
|
|
337
|
+
return names;
|
|
338
|
+
}
|
|
303
339
|
/** Build fetch headers, including HF auth token for huggingface.co URLs */
|
|
304
340
|
function buildHeaders(url) {
|
|
305
341
|
const headers = { "User-Agent": "CamStack/1.0" };
|
|
@@ -465,14 +501,18 @@ async function ensureModel(modelsDir, entry, format, onProgress) {
|
|
|
465
501
|
if (entry.extraFiles) for (const extra of entry.extraFiles) await downloadFile(extra.url, path$1.join(modelsDir, extra.filename));
|
|
466
502
|
const filename = formatEntry.url.split("/").pop() ?? `${entry.id}.${format}`;
|
|
467
503
|
const modelPath = path$1.join(modelsDir, filename);
|
|
504
|
+
const siblings = siblingFilesFor(formatEntry);
|
|
468
505
|
if (fs.existsSync(modelPath)) if (formatEntry.isDirectory && !fs.existsSync(path$1.join(modelPath, "Manifest.json"))) fs.rmSync(modelPath, {
|
|
469
506
|
recursive: true,
|
|
470
507
|
force: true
|
|
471
508
|
});
|
|
472
|
-
else return modelPath;
|
|
509
|
+
else if (siblings.some((f) => !isNonEmptyFile(path$1.join(modelsDir, f)))) {} else return modelPath;
|
|
473
510
|
fs.mkdirSync(modelsDir, { recursive: true });
|
|
474
511
|
if (formatEntry.isDirectory) await downloadDirectory(formatEntry.url, modelPath, formatEntry.files, onProgress);
|
|
475
|
-
else
|
|
512
|
+
else {
|
|
513
|
+
await downloadFile(formatEntry.url, modelPath, (downloaded, total) => onProgress?.(downloaded, total === 0 ? void 0 : total));
|
|
514
|
+
for (const sibling of siblings) await downloadFile(siblingUrl(formatEntry.url, sibling), path$1.join(modelsDir, sibling));
|
|
515
|
+
}
|
|
476
516
|
return modelPath;
|
|
477
517
|
}
|
|
478
518
|
/** Compute the on-disk path for a given model + format, even when not yet downloaded. */
|
|
@@ -489,17 +529,25 @@ function isModelDownloaded(modelsDir, entry, format) {
|
|
|
489
529
|
const modelPath = getModelFilePath(modelsDir, entry, format);
|
|
490
530
|
if (!modelPath || !fs.existsSync(modelPath)) return false;
|
|
491
531
|
if (formatEntry.isDirectory) return fs.existsSync(path$1.join(modelPath, "Manifest.json"));
|
|
492
|
-
|
|
532
|
+
if (fs.statSync(modelPath).size <= 0) return false;
|
|
533
|
+
return siblingFilesFor(formatEntry).every((f) => isNonEmptyFile(path$1.join(modelsDir, f)));
|
|
493
534
|
}
|
|
494
535
|
/** Remove the on-disk model file/directory. Returns true if something was deleted. */
|
|
495
536
|
function deleteModelFromDisk(modelsDir, entry, format) {
|
|
496
537
|
const modelPath = getModelFilePath(modelsDir, entry, format);
|
|
497
538
|
if (!modelPath || !fs.existsSync(modelPath)) return false;
|
|
498
|
-
|
|
539
|
+
const formatEntry = entry.formats[format];
|
|
540
|
+
if (formatEntry?.isDirectory) fs.rmSync(modelPath, {
|
|
499
541
|
recursive: true,
|
|
500
542
|
force: true
|
|
501
543
|
});
|
|
502
|
-
else
|
|
544
|
+
else {
|
|
545
|
+
fs.unlinkSync(modelPath);
|
|
546
|
+
if (formatEntry) for (const sibling of siblingFilesFor(formatEntry)) {
|
|
547
|
+
const sibPath = path$1.join(modelsDir, sibling);
|
|
548
|
+
if (fs.existsSync(sibPath)) fs.unlinkSync(sibPath);
|
|
549
|
+
}
|
|
550
|
+
}
|
|
503
551
|
return true;
|
|
504
552
|
}
|
|
505
553
|
//#endregion
|
|
@@ -536,15 +584,21 @@ var ModelDownloadService = class {
|
|
|
536
584
|
if (!formatEntry) throw new Error(`ModelDownloadService: model "${modelId}" has no ${selectedFormat} format`);
|
|
537
585
|
await this.ensureExtraFiles(modelId);
|
|
538
586
|
const modelPath = this.modelFilePath(entry, selectedFormat);
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
587
|
+
const siblings = siblingFilesFor(formatEntry);
|
|
588
|
+
if (fs.existsSync(modelPath)) {
|
|
589
|
+
if (formatEntry.isDirectory) if (!fs.existsSync(path$1.join(modelPath, "Manifest.json"))) fs.rmSync(modelPath, {
|
|
590
|
+
recursive: true,
|
|
591
|
+
force: true
|
|
592
|
+
});
|
|
593
|
+
else return modelPath;
|
|
594
|
+
else if (siblings.every((f) => isNonEmptyFile(path$1.join(this.modelsDir, f)))) return modelPath;
|
|
595
|
+
}
|
|
545
596
|
fs.mkdirSync(this.modelsDir, { recursive: true });
|
|
546
597
|
if (formatEntry.isDirectory) await this.downloadDirectory(formatEntry.url, modelPath, formatEntry.files, modelId);
|
|
547
|
-
else
|
|
598
|
+
else {
|
|
599
|
+
await downloadFile(formatEntry.url, modelPath, this.onProgress ? (downloaded, total) => this.onProgress(modelId, downloaded, total) : void 0);
|
|
600
|
+
for (const sibling of siblings) await downloadFile(siblingUrl(formatEntry.url, sibling), path$1.join(this.modelsDir, sibling));
|
|
601
|
+
}
|
|
548
602
|
return modelPath;
|
|
549
603
|
}
|
|
550
604
|
/**
|
|
@@ -578,7 +632,8 @@ var ModelDownloadService = class {
|
|
|
578
632
|
const modelPath = this.modelFilePath(entry, selectedFormat);
|
|
579
633
|
if (!fs.existsSync(modelPath)) return false;
|
|
580
634
|
if (formatEntry.isDirectory) return fs.existsSync(path$1.join(modelPath, "Manifest.json"));
|
|
581
|
-
|
|
635
|
+
if (fs.statSync(modelPath).size <= 0) return false;
|
|
636
|
+
return siblingFilesFor(formatEntry).every((f) => isNonEmptyFile(path$1.join(this.modelsDir, f)));
|
|
582
637
|
}
|
|
583
638
|
/** Get the catalog entry for a model by ID. */
|
|
584
639
|
getEntry(modelId) {
|
|
@@ -665,4 +720,4 @@ var ModelDownloadService = class {
|
|
|
665
720
|
}
|
|
666
721
|
};
|
|
667
722
|
//#endregion
|
|
668
|
-
export {
|
|
723
|
+
export { downloadModel as a, getModelFilePath as c, contentTypeFor as d, createAuthenticatedFileServer as f, resolveFilePath as h, downloadFile as i, isModelDownloaded as l, parseTokenizedUrl as m, collectModelFiles as n, ensureModel as o, parseRangeHeader as p, deleteModelFromDisk as r, fetchJson as s, ModelDownloadService as t, createFileDataPlaneHandler as u };
|
|
@@ -301,6 +301,42 @@ function createFileDataPlaneHandler(opts) {
|
|
|
301
301
|
}
|
|
302
302
|
//#endregion
|
|
303
303
|
//#region src/download/model-downloader.ts
|
|
304
|
+
function isNonEmptyFile(filePath) {
|
|
305
|
+
return node_fs.existsSync(filePath) && node_fs.statSync(filePath).size > 0;
|
|
306
|
+
}
|
|
307
|
+
/**
|
|
308
|
+
* Sibling files of a single-file (non-directory) format — extra files the
|
|
309
|
+
* format needs, fetched from the same remote directory as `url` and stored
|
|
310
|
+
* flat alongside the main file in `modelsDir`. Catalog-declared via
|
|
311
|
+
* `formatEntry.files`, e.g. OpenVINO IR lists its `.bin` weights next to the
|
|
312
|
+
* `.xml`. The downloader stays format-agnostic; the convention lives in the
|
|
313
|
+
* catalog data (like `MLPACKAGE_FILES` for the directory case).
|
|
314
|
+
*/
|
|
315
|
+
function siblingFilesFor(formatEntry) {
|
|
316
|
+
return formatEntry.isDirectory ? [] : formatEntry.files ?? [];
|
|
317
|
+
}
|
|
318
|
+
/** Resolve a sibling's remote URL relative to the main file's directory. */
|
|
319
|
+
function siblingUrl(mainUrl, sibling) {
|
|
320
|
+
return mainUrl.replace(/[^/]+$/, sibling);
|
|
321
|
+
}
|
|
322
|
+
/**
|
|
323
|
+
* The relative filenames a model format occupies under `modelsDir` — the main
|
|
324
|
+
* file (URL basename, or `${id}.${format}` fallback), its declared siblings
|
|
325
|
+
* (e.g. the OpenVINO `.bin` next to the `.xml`), and any `extraFiles`. For a
|
|
326
|
+
* directory bundle the single entry is the bundle dir itself (tar/extract
|
|
327
|
+
* recurse into it).
|
|
328
|
+
*
|
|
329
|
+
* Used by model distribution (P2): the hub tars exactly these names from its
|
|
330
|
+
* `modelsDir` and the agent untars them into its own `modelsDir`, so both ends
|
|
331
|
+
* agree on the on-disk layout without re-deriving it.
|
|
332
|
+
*/
|
|
333
|
+
function collectModelFiles(entry, format) {
|
|
334
|
+
const formatEntry = entry.formats[format];
|
|
335
|
+
if (!formatEntry) return [];
|
|
336
|
+
const names = [formatEntry.url.split("/").pop() ?? `${entry.id}.${format}`, ...siblingFilesFor(formatEntry)];
|
|
337
|
+
for (const extra of entry.extraFiles ?? []) names.push(extra.filename);
|
|
338
|
+
return names;
|
|
339
|
+
}
|
|
304
340
|
/** Build fetch headers, including HF auth token for huggingface.co URLs */
|
|
305
341
|
function buildHeaders(url) {
|
|
306
342
|
const headers = { "User-Agent": "CamStack/1.0" };
|
|
@@ -466,14 +502,18 @@ async function ensureModel(modelsDir, entry, format, onProgress) {
|
|
|
466
502
|
if (entry.extraFiles) for (const extra of entry.extraFiles) await downloadFile(extra.url, node_path.join(modelsDir, extra.filename));
|
|
467
503
|
const filename = formatEntry.url.split("/").pop() ?? `${entry.id}.${format}`;
|
|
468
504
|
const modelPath = node_path.join(modelsDir, filename);
|
|
505
|
+
const siblings = siblingFilesFor(formatEntry);
|
|
469
506
|
if (node_fs.existsSync(modelPath)) if (formatEntry.isDirectory && !node_fs.existsSync(node_path.join(modelPath, "Manifest.json"))) node_fs.rmSync(modelPath, {
|
|
470
507
|
recursive: true,
|
|
471
508
|
force: true
|
|
472
509
|
});
|
|
473
|
-
else return modelPath;
|
|
510
|
+
else if (siblings.some((f) => !isNonEmptyFile(node_path.join(modelsDir, f)))) {} else return modelPath;
|
|
474
511
|
node_fs.mkdirSync(modelsDir, { recursive: true });
|
|
475
512
|
if (formatEntry.isDirectory) await downloadDirectory(formatEntry.url, modelPath, formatEntry.files, onProgress);
|
|
476
|
-
else
|
|
513
|
+
else {
|
|
514
|
+
await downloadFile(formatEntry.url, modelPath, (downloaded, total) => onProgress?.(downloaded, total === 0 ? void 0 : total));
|
|
515
|
+
for (const sibling of siblings) await downloadFile(siblingUrl(formatEntry.url, sibling), node_path.join(modelsDir, sibling));
|
|
516
|
+
}
|
|
477
517
|
return modelPath;
|
|
478
518
|
}
|
|
479
519
|
/** Compute the on-disk path for a given model + format, even when not yet downloaded. */
|
|
@@ -490,17 +530,25 @@ function isModelDownloaded(modelsDir, entry, format) {
|
|
|
490
530
|
const modelPath = getModelFilePath(modelsDir, entry, format);
|
|
491
531
|
if (!modelPath || !node_fs.existsSync(modelPath)) return false;
|
|
492
532
|
if (formatEntry.isDirectory) return node_fs.existsSync(node_path.join(modelPath, "Manifest.json"));
|
|
493
|
-
|
|
533
|
+
if (node_fs.statSync(modelPath).size <= 0) return false;
|
|
534
|
+
return siblingFilesFor(formatEntry).every((f) => isNonEmptyFile(node_path.join(modelsDir, f)));
|
|
494
535
|
}
|
|
495
536
|
/** Remove the on-disk model file/directory. Returns true if something was deleted. */
|
|
496
537
|
function deleteModelFromDisk(modelsDir, entry, format) {
|
|
497
538
|
const modelPath = getModelFilePath(modelsDir, entry, format);
|
|
498
539
|
if (!modelPath || !node_fs.existsSync(modelPath)) return false;
|
|
499
|
-
|
|
540
|
+
const formatEntry = entry.formats[format];
|
|
541
|
+
if (formatEntry?.isDirectory) node_fs.rmSync(modelPath, {
|
|
500
542
|
recursive: true,
|
|
501
543
|
force: true
|
|
502
544
|
});
|
|
503
|
-
else
|
|
545
|
+
else {
|
|
546
|
+
node_fs.unlinkSync(modelPath);
|
|
547
|
+
if (formatEntry) for (const sibling of siblingFilesFor(formatEntry)) {
|
|
548
|
+
const sibPath = node_path.join(modelsDir, sibling);
|
|
549
|
+
if (node_fs.existsSync(sibPath)) node_fs.unlinkSync(sibPath);
|
|
550
|
+
}
|
|
551
|
+
}
|
|
504
552
|
return true;
|
|
505
553
|
}
|
|
506
554
|
//#endregion
|
|
@@ -537,15 +585,21 @@ var ModelDownloadService = class {
|
|
|
537
585
|
if (!formatEntry) throw new Error(`ModelDownloadService: model "${modelId}" has no ${selectedFormat} format`);
|
|
538
586
|
await this.ensureExtraFiles(modelId);
|
|
539
587
|
const modelPath = this.modelFilePath(entry, selectedFormat);
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
588
|
+
const siblings = siblingFilesFor(formatEntry);
|
|
589
|
+
if (node_fs.existsSync(modelPath)) {
|
|
590
|
+
if (formatEntry.isDirectory) if (!node_fs.existsSync(node_path.join(modelPath, "Manifest.json"))) node_fs.rmSync(modelPath, {
|
|
591
|
+
recursive: true,
|
|
592
|
+
force: true
|
|
593
|
+
});
|
|
594
|
+
else return modelPath;
|
|
595
|
+
else if (siblings.every((f) => isNonEmptyFile(node_path.join(this.modelsDir, f)))) return modelPath;
|
|
596
|
+
}
|
|
546
597
|
node_fs.mkdirSync(this.modelsDir, { recursive: true });
|
|
547
598
|
if (formatEntry.isDirectory) await this.downloadDirectory(formatEntry.url, modelPath, formatEntry.files, modelId);
|
|
548
|
-
else
|
|
599
|
+
else {
|
|
600
|
+
await downloadFile(formatEntry.url, modelPath, this.onProgress ? (downloaded, total) => this.onProgress(modelId, downloaded, total) : void 0);
|
|
601
|
+
for (const sibling of siblings) await downloadFile(siblingUrl(formatEntry.url, sibling), node_path.join(this.modelsDir, sibling));
|
|
602
|
+
}
|
|
549
603
|
return modelPath;
|
|
550
604
|
}
|
|
551
605
|
/**
|
|
@@ -579,7 +633,8 @@ var ModelDownloadService = class {
|
|
|
579
633
|
const modelPath = this.modelFilePath(entry, selectedFormat);
|
|
580
634
|
if (!node_fs.existsSync(modelPath)) return false;
|
|
581
635
|
if (formatEntry.isDirectory) return node_fs.existsSync(node_path.join(modelPath, "Manifest.json"));
|
|
582
|
-
|
|
636
|
+
if (node_fs.statSync(modelPath).size <= 0) return false;
|
|
637
|
+
return siblingFilesFor(formatEntry).every((f) => isNonEmptyFile(node_path.join(this.modelsDir, f)));
|
|
583
638
|
}
|
|
584
639
|
/** Get the catalog entry for a model by ID. */
|
|
585
640
|
getEntry(modelId) {
|
|
@@ -672,6 +727,12 @@ Object.defineProperty(exports, "ModelDownloadService", {
|
|
|
672
727
|
return ModelDownloadService;
|
|
673
728
|
}
|
|
674
729
|
});
|
|
730
|
+
Object.defineProperty(exports, "collectModelFiles", {
|
|
731
|
+
enumerable: true,
|
|
732
|
+
get: function() {
|
|
733
|
+
return collectModelFiles;
|
|
734
|
+
}
|
|
735
|
+
});
|
|
675
736
|
Object.defineProperty(exports, "contentTypeFor", {
|
|
676
737
|
enumerable: true,
|
|
677
738
|
get: function() {
|