@camstack/system 1.1.0 → 1.1.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.
@@ -318,6 +318,24 @@ function siblingFilesFor(formatEntry) {
318
318
  function siblingUrl(mainUrl, sibling) {
319
319
  return mainUrl.replace(/[^/]+$/, sibling);
320
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
+ }
321
339
  /** Build fetch headers, including HF auth token for huggingface.co URLs */
322
340
  function buildHeaders(url) {
323
341
  const headers = { "User-Agent": "CamStack/1.0" };
@@ -566,15 +584,21 @@ var ModelDownloadService = class {
566
584
  if (!formatEntry) throw new Error(`ModelDownloadService: model "${modelId}" has no ${selectedFormat} format`);
567
585
  await this.ensureExtraFiles(modelId);
568
586
  const modelPath = this.modelFilePath(entry, selectedFormat);
569
- if (fs.existsSync(modelPath)) if (formatEntry.isDirectory) if (!fs.existsSync(path$1.join(modelPath, "Manifest.json"))) fs.rmSync(modelPath, {
570
- recursive: true,
571
- force: true
572
- });
573
- else return modelPath;
574
- else return modelPath;
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
+ }
575
596
  fs.mkdirSync(this.modelsDir, { recursive: true });
576
597
  if (formatEntry.isDirectory) await this.downloadDirectory(formatEntry.url, modelPath, formatEntry.files, modelId);
577
- else await downloadFile(formatEntry.url, modelPath, this.onProgress ? (downloaded, total) => this.onProgress(modelId, downloaded, total) : void 0);
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
+ }
578
602
  return modelPath;
579
603
  }
580
604
  /**
@@ -608,7 +632,8 @@ var ModelDownloadService = class {
608
632
  const modelPath = this.modelFilePath(entry, selectedFormat);
609
633
  if (!fs.existsSync(modelPath)) return false;
610
634
  if (formatEntry.isDirectory) return fs.existsSync(path$1.join(modelPath, "Manifest.json"));
611
- return fs.statSync(modelPath).size > 0;
635
+ if (fs.statSync(modelPath).size <= 0) return false;
636
+ return siblingFilesFor(formatEntry).every((f) => isNonEmptyFile(path$1.join(this.modelsDir, f)));
612
637
  }
613
638
  /** Get the catalog entry for a model by ID. */
614
639
  getEntry(modelId) {
@@ -695,4 +720,4 @@ var ModelDownloadService = class {
695
720
  }
696
721
  };
697
722
  //#endregion
698
- export { ensureModel as a, isModelDownloaded as c, createAuthenticatedFileServer as d, parseRangeHeader as f, downloadModel as i, createFileDataPlaneHandler as l, resolveFilePath as m, deleteModelFromDisk as n, fetchJson as o, parseTokenizedUrl as p, downloadFile as r, getModelFilePath as s, ModelDownloadService as t, contentTypeFor as u };
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 };
@@ -319,6 +319,24 @@ function siblingFilesFor(formatEntry) {
319
319
  function siblingUrl(mainUrl, sibling) {
320
320
  return mainUrl.replace(/[^/]+$/, sibling);
321
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
+ }
322
340
  /** Build fetch headers, including HF auth token for huggingface.co URLs */
323
341
  function buildHeaders(url) {
324
342
  const headers = { "User-Agent": "CamStack/1.0" };
@@ -567,15 +585,21 @@ var ModelDownloadService = class {
567
585
  if (!formatEntry) throw new Error(`ModelDownloadService: model "${modelId}" has no ${selectedFormat} format`);
568
586
  await this.ensureExtraFiles(modelId);
569
587
  const modelPath = this.modelFilePath(entry, selectedFormat);
570
- if (node_fs.existsSync(modelPath)) if (formatEntry.isDirectory) if (!node_fs.existsSync(node_path.join(modelPath, "Manifest.json"))) node_fs.rmSync(modelPath, {
571
- recursive: true,
572
- force: true
573
- });
574
- else return modelPath;
575
- else return modelPath;
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
+ }
576
597
  node_fs.mkdirSync(this.modelsDir, { recursive: true });
577
598
  if (formatEntry.isDirectory) await this.downloadDirectory(formatEntry.url, modelPath, formatEntry.files, modelId);
578
- else await downloadFile(formatEntry.url, modelPath, this.onProgress ? (downloaded, total) => this.onProgress(modelId, downloaded, total) : void 0);
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
+ }
579
603
  return modelPath;
580
604
  }
581
605
  /**
@@ -609,7 +633,8 @@ var ModelDownloadService = class {
609
633
  const modelPath = this.modelFilePath(entry, selectedFormat);
610
634
  if (!node_fs.existsSync(modelPath)) return false;
611
635
  if (formatEntry.isDirectory) return node_fs.existsSync(node_path.join(modelPath, "Manifest.json"));
612
- return node_fs.statSync(modelPath).size > 0;
636
+ if (node_fs.statSync(modelPath).size <= 0) return false;
637
+ return siblingFilesFor(formatEntry).every((f) => isNonEmptyFile(node_path.join(this.modelsDir, f)));
613
638
  }
614
639
  /** Get the catalog entry for a model by ID. */
615
640
  getEntry(modelId) {
@@ -702,6 +727,12 @@ Object.defineProperty(exports, "ModelDownloadService", {
702
727
  return ModelDownloadService;
703
728
  }
704
729
  });
730
+ Object.defineProperty(exports, "collectModelFiles", {
731
+ enumerable: true,
732
+ get: function() {
733
+ return collectModelFiles;
734
+ }
735
+ });
705
736
  Object.defineProperty(exports, "contentTypeFor", {
706
737
  enumerable: true,
707
738
  get: function() {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camstack/system",
3
- "version": "1.1.0",
3
+ "version": "1.1.2",
4
4
  "description": "Core addon for CamStack — builtins, pipeline, process management, auth, logging, events",
5
5
  "keywords": [
6
6
  "camstack",