@camstack/addon-ai 0.4.29 → 0.4.30
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.js +15 -159
- package/dist/addon.mjs +27 -170
- package/package.json +1 -1
package/dist/addon.js
CHANGED
|
@@ -4,14 +4,11 @@ Object.defineProperties(exports, {
|
|
|
4
4
|
});
|
|
5
5
|
const require_chunk = require("./chunk-CVvi-lCc.js");
|
|
6
6
|
let node_path = require("node:path");
|
|
7
|
-
let node_path$1 = require_chunk.__toESM(node_path, 1);
|
|
8
7
|
node_path = require_chunk.__toESM(node_path);
|
|
9
8
|
let node_crypto = require("node:crypto");
|
|
10
9
|
let node_net = require("node:net");
|
|
11
10
|
let node_fs = require("node:fs");
|
|
12
|
-
|
|
13
|
-
let node_util = require("node:util");
|
|
14
|
-
let node_zlib = require("node:zlib");
|
|
11
|
+
let _camstack_system_addon_utils = require("@camstack/system/addon-utils");
|
|
15
12
|
let node_fs_promises = require("node:fs/promises");
|
|
16
13
|
node_fs_promises = require_chunk.__toESM(node_fs_promises);
|
|
17
14
|
let node_child_process = require("node:child_process");
|
|
@@ -61226,12 +61223,12 @@ var require_auth_config = /* @__PURE__ */ require_chunk.__commonJSMin(((exports,
|
|
|
61226
61223
|
});
|
|
61227
61224
|
module.exports = __toCommonJS(auth_config_exports);
|
|
61228
61225
|
var fs$1 = __toESM(require("fs"));
|
|
61229
|
-
var path$
|
|
61226
|
+
var path$1 = __toESM(require("path"));
|
|
61230
61227
|
var import_token_util = require_token_util();
|
|
61231
61228
|
function getAuthConfigPath() {
|
|
61232
61229
|
const dataDir = (0, import_token_util.getVercelDataDir)();
|
|
61233
61230
|
if (!dataDir) throw new Error(`Unable to find Vercel CLI data directory. Your platform: ${process.platform}. Supported: darwin, linux, win32.`);
|
|
61234
|
-
return path$
|
|
61231
|
+
return path$1.join(dataDir, "auth.json");
|
|
61235
61232
|
}
|
|
61236
61233
|
function readAuthConfig() {
|
|
61237
61234
|
try {
|
|
@@ -61246,7 +61243,7 @@ var require_auth_config = /* @__PURE__ */ require_chunk.__commonJSMin(((exports,
|
|
|
61246
61243
|
}
|
|
61247
61244
|
function writeAuthConfig(config) {
|
|
61248
61245
|
const authPath = getAuthConfigPath();
|
|
61249
|
-
const authDir = path$
|
|
61246
|
+
const authDir = path$1.dirname(authPath);
|
|
61250
61247
|
if (!fs$1.existsSync(authDir)) fs$1.mkdirSync(authDir, {
|
|
61251
61248
|
mode: 504,
|
|
61252
61249
|
recursive: true
|
|
@@ -61384,7 +61381,7 @@ var require_token_util = /* @__PURE__ */ require_chunk.__commonJSMin(((exports,
|
|
|
61384
61381
|
saveToken: () => saveToken
|
|
61385
61382
|
});
|
|
61386
61383
|
module.exports = __toCommonJS(token_util_exports);
|
|
61387
|
-
var path
|
|
61384
|
+
var path = __toESM(require("path"));
|
|
61388
61385
|
var fs = __toESM(require("fs"));
|
|
61389
61386
|
var import_token_error = require_token_error();
|
|
61390
61387
|
var import_token_io = require_token_io();
|
|
@@ -61395,7 +61392,7 @@ var require_token_util = /* @__PURE__ */ require_chunk.__commonJSMin(((exports,
|
|
|
61395
61392
|
const vercelFolder = "com.vercel.cli";
|
|
61396
61393
|
const dataDir = (0, import_token_io.getUserDataDir)();
|
|
61397
61394
|
if (!dataDir) return null;
|
|
61398
|
-
return path
|
|
61395
|
+
return path.join(dataDir, vercelFolder);
|
|
61399
61396
|
}
|
|
61400
61397
|
async function getVercelToken(options) {
|
|
61401
61398
|
const authConfig = (0, import_auth_config.readAuthConfig)();
|
|
@@ -61443,7 +61440,7 @@ var require_token_util = /* @__PURE__ */ require_chunk.__commonJSMin(((exports,
|
|
|
61443
61440
|
function findProjectInfo() {
|
|
61444
61441
|
const dir = (0, import_token_io.findRootDir)();
|
|
61445
61442
|
if (!dir) throw new import_token_error.VercelOidcTokenError("Unable to find project root directory. Have you linked your project with `vc link?`");
|
|
61446
|
-
const prjPath = path
|
|
61443
|
+
const prjPath = path.join(dir, ".vercel", "project.json");
|
|
61447
61444
|
if (!fs.existsSync(prjPath)) throw new import_token_error.VercelOidcTokenError("project.json not found, have you linked your project with `vc link?`");
|
|
61448
61445
|
const prj = JSON.parse(fs.readFileSync(prjPath, "utf8"));
|
|
61449
61446
|
if (typeof prj.projectId !== "string" && typeof prj.orgId !== "string") throw new TypeError("Expected a string-valued projectId property. Try running `vc link` to re-link your project.");
|
|
@@ -61455,9 +61452,9 @@ var require_token_util = /* @__PURE__ */ require_chunk.__commonJSMin(((exports,
|
|
|
61455
61452
|
function saveToken(token, projectId) {
|
|
61456
61453
|
const dir = (0, import_token_io.getUserDataDir)();
|
|
61457
61454
|
if (!dir) throw new import_token_error.VercelOidcTokenError("Unable to find user data directory. Please reach out to Vercel support.");
|
|
61458
|
-
const tokenPath = path
|
|
61455
|
+
const tokenPath = path.join(dir, "com.vercel.token", `${projectId}.json`);
|
|
61459
61456
|
const tokenJson = JSON.stringify(token);
|
|
61460
|
-
fs.mkdirSync(path
|
|
61457
|
+
fs.mkdirSync(path.dirname(tokenPath), {
|
|
61461
61458
|
mode: 504,
|
|
61462
61459
|
recursive: true
|
|
61463
61460
|
});
|
|
@@ -61467,7 +61464,7 @@ var require_token_util = /* @__PURE__ */ require_chunk.__commonJSMin(((exports,
|
|
|
61467
61464
|
function loadToken(projectId) {
|
|
61468
61465
|
const dir = (0, import_token_io.getUserDataDir)();
|
|
61469
61466
|
if (!dir) throw new import_token_error.VercelOidcTokenError("Unable to find user data directory. Please reach out to Vercel support.");
|
|
61470
|
-
const tokenPath = path
|
|
61467
|
+
const tokenPath = path.join(dir, "com.vercel.token", `${projectId}.json`);
|
|
61471
61468
|
if (!fs.existsSync(tokenPath)) return null;
|
|
61472
61469
|
const token = JSON.parse(fs.readFileSync(tokenPath, "utf8"));
|
|
61473
61470
|
assertVercelOidcTokenResponse(token);
|
|
@@ -73473,147 +73470,6 @@ function entryForRef(ref) {
|
|
|
73473
73470
|
};
|
|
73474
73471
|
}
|
|
73475
73472
|
//#endregion
|
|
73476
|
-
//#region ../system/dist/file-data-plane-BhKdxJgf.mjs
|
|
73477
|
-
function isNonEmptyFile(filePath) {
|
|
73478
|
-
return node_fs.existsSync(filePath) && node_fs.statSync(filePath).size > 0;
|
|
73479
|
-
}
|
|
73480
|
-
/**
|
|
73481
|
-
* Sibling files of a single-file (non-directory) format — extra files the
|
|
73482
|
-
* format needs, fetched from the same remote directory as `url` and stored
|
|
73483
|
-
* flat alongside the main file in `modelsDir`. Catalog-declared via
|
|
73484
|
-
* `formatEntry.files`, e.g. OpenVINO IR lists its `.bin` weights next to the
|
|
73485
|
-
* `.xml`. The downloader stays format-agnostic; the convention lives in the
|
|
73486
|
-
* catalog data (like `MLPACKAGE_FILES` for the directory case).
|
|
73487
|
-
*/
|
|
73488
|
-
function siblingFilesFor(formatEntry) {
|
|
73489
|
-
return formatEntry.isDirectory ? [] : formatEntry.files ?? [];
|
|
73490
|
-
}
|
|
73491
|
-
/** Build fetch headers, including HF auth token for huggingface.co URLs */
|
|
73492
|
-
function buildHeaders(url) {
|
|
73493
|
-
const headers = { "User-Agent": "CamStack/1.0" };
|
|
73494
|
-
const hfToken = process.env["HF_TOKEN"] ?? process.env["HUGGING_FACE_HUB_TOKEN"];
|
|
73495
|
-
if (hfToken && url.includes("huggingface.co")) headers["Authorization"] = `Bearer ${hfToken}`;
|
|
73496
|
-
return headers;
|
|
73497
|
-
}
|
|
73498
|
-
var DEFAULT_MAX_REDIRECTS = 5;
|
|
73499
|
-
function normalizeDownloadOptions(third) {
|
|
73500
|
-
if (typeof third === "function") return { onProgress: third };
|
|
73501
|
-
return third ?? {};
|
|
73502
|
-
}
|
|
73503
|
-
function isRedirectStatus(status) {
|
|
73504
|
-
return status === 301 || status === 302 || status === 303 || status === 307 || status === 308;
|
|
73505
|
-
}
|
|
73506
|
-
function resolveRedirectUrl(current, location) {
|
|
73507
|
-
return new URL(location, current);
|
|
73508
|
-
}
|
|
73509
|
-
async function downloadFile(url, destPath, onProgressOrOptions) {
|
|
73510
|
-
if (node_fs.existsSync(destPath)) return destPath;
|
|
73511
|
-
const opts = normalizeDownloadOptions(onProgressOrOptions);
|
|
73512
|
-
const fetchImpl = opts.fetchImpl ?? fetch;
|
|
73513
|
-
const maxRedirects = opts.maxRedirects ?? DEFAULT_MAX_REDIRECTS;
|
|
73514
|
-
node_fs.mkdirSync(node_path$1.dirname(destPath), { recursive: true });
|
|
73515
|
-
const tmpPath = destPath + ".downloading";
|
|
73516
|
-
try {
|
|
73517
|
-
let current = url;
|
|
73518
|
-
const seen = /* @__PURE__ */ new Set();
|
|
73519
|
-
let response;
|
|
73520
|
-
const manual = opts.redirectPolicy !== void 0;
|
|
73521
|
-
for (let hop = 0; hop <= maxRedirects; hop++) {
|
|
73522
|
-
const parsed = new URL(current);
|
|
73523
|
-
if (opts.redirectPolicy) opts.redirectPolicy(parsed, hop);
|
|
73524
|
-
if (seen.has(parsed.href)) throw new Error(`Redirect loop detected at ${parsed.href}`);
|
|
73525
|
-
seen.add(parsed.href);
|
|
73526
|
-
const controller = opts.timeoutMs !== void 0 ? new AbortController() : void 0;
|
|
73527
|
-
const timer = controller && opts.timeoutMs !== void 0 ? setTimeout(() => controller.abort(), opts.timeoutMs) : void 0;
|
|
73528
|
-
try {
|
|
73529
|
-
response = await fetchImpl(current, {
|
|
73530
|
-
redirect: manual ? "manual" : "follow",
|
|
73531
|
-
headers: buildHeaders(current),
|
|
73532
|
-
...controller ? { signal: controller.signal } : {}
|
|
73533
|
-
});
|
|
73534
|
-
} finally {
|
|
73535
|
-
if (timer) clearTimeout(timer);
|
|
73536
|
-
}
|
|
73537
|
-
if (manual && isRedirectStatus(response.status)) {
|
|
73538
|
-
const location = response.headers.get("location");
|
|
73539
|
-
if (!location) throw new Error(`Redirect ${response.status} missing Location header`);
|
|
73540
|
-
if (hop >= maxRedirects) throw new Error(`Too many redirects (max ${maxRedirects}) downloading ${url}`);
|
|
73541
|
-
current = resolveRedirectUrl(current, location).href;
|
|
73542
|
-
continue;
|
|
73543
|
-
}
|
|
73544
|
-
break;
|
|
73545
|
-
}
|
|
73546
|
-
if (!response) throw new Error(`No response downloading ${url}`);
|
|
73547
|
-
if (manual && isRedirectStatus(response.status)) throw new Error(`Too many redirects (max ${maxRedirects}) downloading ${url}`);
|
|
73548
|
-
if (!response.ok) throw new Error(`HTTP ${response.status} downloading ${url}`);
|
|
73549
|
-
if (!response.body) throw new Error(`No response body from ${url}`);
|
|
73550
|
-
const total = parseInt(response.headers.get("content-length") ?? "0", 10);
|
|
73551
|
-
let downloaded = 0;
|
|
73552
|
-
const fileStream = node_fs.createWriteStream(tmpPath);
|
|
73553
|
-
const reader = response.body.getReader();
|
|
73554
|
-
try {
|
|
73555
|
-
for (;;) {
|
|
73556
|
-
const { done, value } = await reader.read();
|
|
73557
|
-
if (done || !value) break;
|
|
73558
|
-
downloaded += value.length;
|
|
73559
|
-
if (opts.maxBytes !== void 0 && downloaded > opts.maxBytes) throw new Error(`Downloaded ${downloaded} bytes exceeds the ${opts.maxBytes}-byte limit`);
|
|
73560
|
-
fileStream.write(value);
|
|
73561
|
-
opts.onProgress?.(downloaded, total);
|
|
73562
|
-
}
|
|
73563
|
-
} finally {
|
|
73564
|
-
fileStream.end();
|
|
73565
|
-
await new Promise((resolve, reject) => {
|
|
73566
|
-
fileStream.on("finish", resolve);
|
|
73567
|
-
fileStream.on("error", reject);
|
|
73568
|
-
});
|
|
73569
|
-
}
|
|
73570
|
-
node_fs.renameSync(tmpPath, destPath);
|
|
73571
|
-
return destPath;
|
|
73572
|
-
} catch (err) {
|
|
73573
|
-
try {
|
|
73574
|
-
node_fs.unlinkSync(tmpPath);
|
|
73575
|
-
} catch {}
|
|
73576
|
-
throw err;
|
|
73577
|
-
}
|
|
73578
|
-
}
|
|
73579
|
-
/** Compute the on-disk path for a given model + format, even when not yet downloaded. */
|
|
73580
|
-
function getModelFilePath(modelsDir, entry, format) {
|
|
73581
|
-
const formatEntry = entry.formats[format];
|
|
73582
|
-
if (!formatEntry) return null;
|
|
73583
|
-
const filename = formatEntry.url.split("/").pop() ?? `${entry.id}.${format}`;
|
|
73584
|
-
return node_path$1.join(modelsDir, filename);
|
|
73585
|
-
}
|
|
73586
|
-
/** True iff the model file (or `Manifest.json` for directory bundles) exists and is non-empty. */
|
|
73587
|
-
function isModelDownloaded(modelsDir, entry, format) {
|
|
73588
|
-
const formatEntry = entry.formats[format];
|
|
73589
|
-
if (!formatEntry) return false;
|
|
73590
|
-
const modelPath = getModelFilePath(modelsDir, entry, format);
|
|
73591
|
-
if (!modelPath || !node_fs.existsSync(modelPath)) return false;
|
|
73592
|
-
if (formatEntry.isDirectory) return node_fs.existsSync(node_path$1.join(modelPath, "Manifest.json"));
|
|
73593
|
-
if (node_fs.statSync(modelPath).size <= 0) return false;
|
|
73594
|
-
return siblingFilesFor(formatEntry).every((f) => isNonEmptyFile(node_path$1.join(modelsDir, f)));
|
|
73595
|
-
}
|
|
73596
|
-
/** Remove the on-disk model file/directory. Returns true if something was deleted. */
|
|
73597
|
-
function deleteModelFromDisk(modelsDir, entry, format) {
|
|
73598
|
-
const modelPath = getModelFilePath(modelsDir, entry, format);
|
|
73599
|
-
if (!modelPath || !node_fs.existsSync(modelPath)) return false;
|
|
73600
|
-
const formatEntry = entry.formats[format];
|
|
73601
|
-
if (formatEntry?.isDirectory) node_fs.rmSync(modelPath, {
|
|
73602
|
-
recursive: true,
|
|
73603
|
-
force: true
|
|
73604
|
-
});
|
|
73605
|
-
else {
|
|
73606
|
-
node_fs.unlinkSync(modelPath);
|
|
73607
|
-
if (formatEntry) for (const sibling of siblingFilesFor(formatEntry)) {
|
|
73608
|
-
const sibPath = node_path$1.join(modelsDir, sibling);
|
|
73609
|
-
if (node_fs.existsSync(sibPath)) node_fs.unlinkSync(sibPath);
|
|
73610
|
-
}
|
|
73611
|
-
}
|
|
73612
|
-
return true;
|
|
73613
|
-
}
|
|
73614
|
-
(0, node_util.promisify)(node_zlib.brotliCompress);
|
|
73615
|
-
(0, node_util.promisify)(node_zlib.gzip);
|
|
73616
|
-
//#endregion
|
|
73617
73473
|
//#region src/runtime/model-ops.ts
|
|
73618
73474
|
/**
|
|
73619
73475
|
* Default `RuntimeModelOps` — the ONLY place the reused object-detection model
|
|
@@ -73677,7 +73533,7 @@ function createDefaultModelOps(modelsDir) {
|
|
|
73677
73533
|
downloadedBytes: carried,
|
|
73678
73534
|
...totalBytes > 0 ? { totalBytes } : {}
|
|
73679
73535
|
});
|
|
73680
|
-
await downloadFile(file.url, file.destPath, (downloaded) => {
|
|
73536
|
+
await (0, _camstack_system_addon_utils.downloadFile)(file.url, file.destPath, (downloaded) => {
|
|
73681
73537
|
onProgress({
|
|
73682
73538
|
file: file.filename,
|
|
73683
73539
|
fileIndex: index + 1,
|
|
@@ -73688,18 +73544,18 @@ function createDefaultModelOps(modelsDir) {
|
|
|
73688
73544
|
});
|
|
73689
73545
|
carried += (0, node_fs.existsSync)(file.destPath) ? (0, node_fs.statSync)(file.destPath).size : file.expectedBytes;
|
|
73690
73546
|
}
|
|
73691
|
-
const main = getModelFilePath(modelsDir, entry, GGUF);
|
|
73547
|
+
const main = (0, _camstack_system_addon_utils.getModelFilePath)(modelsDir, entry, GGUF);
|
|
73692
73548
|
if (main === null) throw new Error(`no gguf path for model ${entry.id}`);
|
|
73693
73549
|
return main;
|
|
73694
73550
|
},
|
|
73695
|
-
isDownloaded: (entry) => isModelDownloaded(modelsDir, entry, GGUF),
|
|
73551
|
+
isDownloaded: (entry) => (0, _camstack_system_addon_utils.isModelDownloaded)(modelsDir, entry, GGUF),
|
|
73696
73552
|
pathFor: (entry) => {
|
|
73697
|
-
const p = getModelFilePath(modelsDir, entry, GGUF);
|
|
73553
|
+
const p = (0, _camstack_system_addon_utils.getModelFilePath)(modelsDir, entry, GGUF);
|
|
73698
73554
|
if (p === null) throw new Error(`no gguf path for model ${entry.id}`);
|
|
73699
73555
|
return p;
|
|
73700
73556
|
},
|
|
73701
73557
|
delete: async (entry) => {
|
|
73702
|
-
deleteModelFromDisk(modelsDir, entry, GGUF);
|
|
73558
|
+
(0, _camstack_system_addon_utils.deleteModelFromDisk)(modelsDir, entry, GGUF);
|
|
73703
73559
|
},
|
|
73704
73560
|
extraFilePath: (_entry, filename) => node_path.join(modelsDir, filename)
|
|
73705
73561
|
};
|
package/dist/addon.mjs
CHANGED
|
@@ -1,11 +1,9 @@
|
|
|
1
1
|
import { createRequire } from "node:module";
|
|
2
|
-
import * as path
|
|
2
|
+
import * as path from "node:path";
|
|
3
3
|
import { createHash, randomUUID } from "node:crypto";
|
|
4
4
|
import { connect, createServer } from "node:net";
|
|
5
|
-
import * as fs from "node:fs";
|
|
6
5
|
import { createReadStream, existsSync, statSync } from "node:fs";
|
|
7
|
-
import {
|
|
8
|
-
import { brotliCompress, gzip } from "node:zlib";
|
|
6
|
+
import { deleteModelFromDisk, downloadFile, getModelFilePath, isModelDownloaded } from "@camstack/system/addon-utils";
|
|
9
7
|
import * as fsp from "node:fs/promises";
|
|
10
8
|
import { spawn } from "node:child_process";
|
|
11
9
|
//#region \0rolldown/runtime.js
|
|
@@ -61251,7 +61249,7 @@ var require_auth_config = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
|
61251
61249
|
writeAuthConfig: () => writeAuthConfig
|
|
61252
61250
|
});
|
|
61253
61251
|
module.exports = __toCommonJS(auth_config_exports);
|
|
61254
|
-
var fs$
|
|
61252
|
+
var fs$1 = __toESM(__require("fs"));
|
|
61255
61253
|
var path$2 = __toESM(__require("path"));
|
|
61256
61254
|
var import_token_util = require_token_util();
|
|
61257
61255
|
function getAuthConfigPath() {
|
|
@@ -61262,8 +61260,8 @@ var require_auth_config = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
|
61262
61260
|
function readAuthConfig() {
|
|
61263
61261
|
try {
|
|
61264
61262
|
const authPath = getAuthConfigPath();
|
|
61265
|
-
if (!fs$
|
|
61266
|
-
const content = fs$
|
|
61263
|
+
if (!fs$1.existsSync(authPath)) return null;
|
|
61264
|
+
const content = fs$1.readFileSync(authPath, "utf8");
|
|
61267
61265
|
if (!content) return null;
|
|
61268
61266
|
return JSON.parse(content);
|
|
61269
61267
|
} catch (error) {
|
|
@@ -61273,11 +61271,11 @@ var require_auth_config = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
|
61273
61271
|
function writeAuthConfig(config) {
|
|
61274
61272
|
const authPath = getAuthConfigPath();
|
|
61275
61273
|
const authDir = path$2.dirname(authPath);
|
|
61276
|
-
if (!fs$
|
|
61274
|
+
if (!fs$1.existsSync(authDir)) fs$1.mkdirSync(authDir, {
|
|
61277
61275
|
mode: 504,
|
|
61278
61276
|
recursive: true
|
|
61279
61277
|
});
|
|
61280
|
-
fs$
|
|
61278
|
+
fs$1.writeFileSync(authPath, JSON.stringify(config, null, 2), { mode: 384 });
|
|
61281
61279
|
}
|
|
61282
61280
|
function isValidAccessToken(authConfig, expirationBufferMs = 0) {
|
|
61283
61281
|
if (!authConfig.token) return false;
|
|
@@ -61410,8 +61408,8 @@ var require_token_util = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
|
61410
61408
|
saveToken: () => saveToken
|
|
61411
61409
|
});
|
|
61412
61410
|
module.exports = __toCommonJS(token_util_exports);
|
|
61413
|
-
var path = __toESM(__require("path"));
|
|
61414
|
-
var fs
|
|
61411
|
+
var path$1 = __toESM(__require("path"));
|
|
61412
|
+
var fs = __toESM(__require("fs"));
|
|
61415
61413
|
var import_token_error = require_token_error();
|
|
61416
61414
|
var import_token_io = require_token_io();
|
|
61417
61415
|
var import_auth_config = require_auth_config();
|
|
@@ -61421,7 +61419,7 @@ var require_token_util = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
|
61421
61419
|
const vercelFolder = "com.vercel.cli";
|
|
61422
61420
|
const dataDir = (0, import_token_io.getUserDataDir)();
|
|
61423
61421
|
if (!dataDir) return null;
|
|
61424
|
-
return path.join(dataDir, vercelFolder);
|
|
61422
|
+
return path$1.join(dataDir, vercelFolder);
|
|
61425
61423
|
}
|
|
61426
61424
|
async function getVercelToken(options) {
|
|
61427
61425
|
const authConfig = (0, import_auth_config.readAuthConfig)();
|
|
@@ -61469,9 +61467,9 @@ var require_token_util = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
|
61469
61467
|
function findProjectInfo() {
|
|
61470
61468
|
const dir = (0, import_token_io.findRootDir)();
|
|
61471
61469
|
if (!dir) throw new import_token_error.VercelOidcTokenError("Unable to find project root directory. Have you linked your project with `vc link?`");
|
|
61472
|
-
const prjPath = path.join(dir, ".vercel", "project.json");
|
|
61473
|
-
if (!fs
|
|
61474
|
-
const prj = JSON.parse(fs
|
|
61470
|
+
const prjPath = path$1.join(dir, ".vercel", "project.json");
|
|
61471
|
+
if (!fs.existsSync(prjPath)) throw new import_token_error.VercelOidcTokenError("project.json not found, have you linked your project with `vc link?`");
|
|
61472
|
+
const prj = JSON.parse(fs.readFileSync(prjPath, "utf8"));
|
|
61475
61473
|
if (typeof prj.projectId !== "string" && typeof prj.orgId !== "string") throw new TypeError("Expected a string-valued projectId property. Try running `vc link` to re-link your project.");
|
|
61476
61474
|
return {
|
|
61477
61475
|
projectId: prj.projectId,
|
|
@@ -61481,21 +61479,21 @@ var require_token_util = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
|
61481
61479
|
function saveToken(token, projectId) {
|
|
61482
61480
|
const dir = (0, import_token_io.getUserDataDir)();
|
|
61483
61481
|
if (!dir) throw new import_token_error.VercelOidcTokenError("Unable to find user data directory. Please reach out to Vercel support.");
|
|
61484
|
-
const tokenPath = path.join(dir, "com.vercel.token", `${projectId}.json`);
|
|
61482
|
+
const tokenPath = path$1.join(dir, "com.vercel.token", `${projectId}.json`);
|
|
61485
61483
|
const tokenJson = JSON.stringify(token);
|
|
61486
|
-
fs
|
|
61484
|
+
fs.mkdirSync(path$1.dirname(tokenPath), {
|
|
61487
61485
|
mode: 504,
|
|
61488
61486
|
recursive: true
|
|
61489
61487
|
});
|
|
61490
|
-
fs
|
|
61491
|
-
fs
|
|
61488
|
+
fs.writeFileSync(tokenPath, tokenJson);
|
|
61489
|
+
fs.chmodSync(tokenPath, 432);
|
|
61492
61490
|
}
|
|
61493
61491
|
function loadToken(projectId) {
|
|
61494
61492
|
const dir = (0, import_token_io.getUserDataDir)();
|
|
61495
61493
|
if (!dir) throw new import_token_error.VercelOidcTokenError("Unable to find user data directory. Please reach out to Vercel support.");
|
|
61496
|
-
const tokenPath = path.join(dir, "com.vercel.token", `${projectId}.json`);
|
|
61497
|
-
if (!fs
|
|
61498
|
-
const token = JSON.parse(fs
|
|
61494
|
+
const tokenPath = path$1.join(dir, "com.vercel.token", `${projectId}.json`);
|
|
61495
|
+
if (!fs.existsSync(tokenPath)) return null;
|
|
61496
|
+
const token = JSON.parse(fs.readFileSync(tokenPath, "utf8"));
|
|
61499
61497
|
assertVercelOidcTokenResponse(token);
|
|
61500
61498
|
return token;
|
|
61501
61499
|
}
|
|
@@ -73499,147 +73497,6 @@ function entryForRef(ref) {
|
|
|
73499
73497
|
};
|
|
73500
73498
|
}
|
|
73501
73499
|
//#endregion
|
|
73502
|
-
//#region ../system/dist/file-data-plane-BhKdxJgf.mjs
|
|
73503
|
-
function isNonEmptyFile(filePath) {
|
|
73504
|
-
return fs.existsSync(filePath) && fs.statSync(filePath).size > 0;
|
|
73505
|
-
}
|
|
73506
|
-
/**
|
|
73507
|
-
* Sibling files of a single-file (non-directory) format — extra files the
|
|
73508
|
-
* format needs, fetched from the same remote directory as `url` and stored
|
|
73509
|
-
* flat alongside the main file in `modelsDir`. Catalog-declared via
|
|
73510
|
-
* `formatEntry.files`, e.g. OpenVINO IR lists its `.bin` weights next to the
|
|
73511
|
-
* `.xml`. The downloader stays format-agnostic; the convention lives in the
|
|
73512
|
-
* catalog data (like `MLPACKAGE_FILES` for the directory case).
|
|
73513
|
-
*/
|
|
73514
|
-
function siblingFilesFor(formatEntry) {
|
|
73515
|
-
return formatEntry.isDirectory ? [] : formatEntry.files ?? [];
|
|
73516
|
-
}
|
|
73517
|
-
/** Build fetch headers, including HF auth token for huggingface.co URLs */
|
|
73518
|
-
function buildHeaders(url) {
|
|
73519
|
-
const headers = { "User-Agent": "CamStack/1.0" };
|
|
73520
|
-
const hfToken = process.env["HF_TOKEN"] ?? process.env["HUGGING_FACE_HUB_TOKEN"];
|
|
73521
|
-
if (hfToken && url.includes("huggingface.co")) headers["Authorization"] = `Bearer ${hfToken}`;
|
|
73522
|
-
return headers;
|
|
73523
|
-
}
|
|
73524
|
-
var DEFAULT_MAX_REDIRECTS = 5;
|
|
73525
|
-
function normalizeDownloadOptions(third) {
|
|
73526
|
-
if (typeof third === "function") return { onProgress: third };
|
|
73527
|
-
return third ?? {};
|
|
73528
|
-
}
|
|
73529
|
-
function isRedirectStatus(status) {
|
|
73530
|
-
return status === 301 || status === 302 || status === 303 || status === 307 || status === 308;
|
|
73531
|
-
}
|
|
73532
|
-
function resolveRedirectUrl(current, location) {
|
|
73533
|
-
return new URL(location, current);
|
|
73534
|
-
}
|
|
73535
|
-
async function downloadFile(url, destPath, onProgressOrOptions) {
|
|
73536
|
-
if (fs.existsSync(destPath)) return destPath;
|
|
73537
|
-
const opts = normalizeDownloadOptions(onProgressOrOptions);
|
|
73538
|
-
const fetchImpl = opts.fetchImpl ?? fetch;
|
|
73539
|
-
const maxRedirects = opts.maxRedirects ?? DEFAULT_MAX_REDIRECTS;
|
|
73540
|
-
fs.mkdirSync(path$1.dirname(destPath), { recursive: true });
|
|
73541
|
-
const tmpPath = destPath + ".downloading";
|
|
73542
|
-
try {
|
|
73543
|
-
let current = url;
|
|
73544
|
-
const seen = /* @__PURE__ */ new Set();
|
|
73545
|
-
let response;
|
|
73546
|
-
const manual = opts.redirectPolicy !== void 0;
|
|
73547
|
-
for (let hop = 0; hop <= maxRedirects; hop++) {
|
|
73548
|
-
const parsed = new URL(current);
|
|
73549
|
-
if (opts.redirectPolicy) opts.redirectPolicy(parsed, hop);
|
|
73550
|
-
if (seen.has(parsed.href)) throw new Error(`Redirect loop detected at ${parsed.href}`);
|
|
73551
|
-
seen.add(parsed.href);
|
|
73552
|
-
const controller = opts.timeoutMs !== void 0 ? new AbortController() : void 0;
|
|
73553
|
-
const timer = controller && opts.timeoutMs !== void 0 ? setTimeout(() => controller.abort(), opts.timeoutMs) : void 0;
|
|
73554
|
-
try {
|
|
73555
|
-
response = await fetchImpl(current, {
|
|
73556
|
-
redirect: manual ? "manual" : "follow",
|
|
73557
|
-
headers: buildHeaders(current),
|
|
73558
|
-
...controller ? { signal: controller.signal } : {}
|
|
73559
|
-
});
|
|
73560
|
-
} finally {
|
|
73561
|
-
if (timer) clearTimeout(timer);
|
|
73562
|
-
}
|
|
73563
|
-
if (manual && isRedirectStatus(response.status)) {
|
|
73564
|
-
const location = response.headers.get("location");
|
|
73565
|
-
if (!location) throw new Error(`Redirect ${response.status} missing Location header`);
|
|
73566
|
-
if (hop >= maxRedirects) throw new Error(`Too many redirects (max ${maxRedirects}) downloading ${url}`);
|
|
73567
|
-
current = resolveRedirectUrl(current, location).href;
|
|
73568
|
-
continue;
|
|
73569
|
-
}
|
|
73570
|
-
break;
|
|
73571
|
-
}
|
|
73572
|
-
if (!response) throw new Error(`No response downloading ${url}`);
|
|
73573
|
-
if (manual && isRedirectStatus(response.status)) throw new Error(`Too many redirects (max ${maxRedirects}) downloading ${url}`);
|
|
73574
|
-
if (!response.ok) throw new Error(`HTTP ${response.status} downloading ${url}`);
|
|
73575
|
-
if (!response.body) throw new Error(`No response body from ${url}`);
|
|
73576
|
-
const total = parseInt(response.headers.get("content-length") ?? "0", 10);
|
|
73577
|
-
let downloaded = 0;
|
|
73578
|
-
const fileStream = fs.createWriteStream(tmpPath);
|
|
73579
|
-
const reader = response.body.getReader();
|
|
73580
|
-
try {
|
|
73581
|
-
for (;;) {
|
|
73582
|
-
const { done, value } = await reader.read();
|
|
73583
|
-
if (done || !value) break;
|
|
73584
|
-
downloaded += value.length;
|
|
73585
|
-
if (opts.maxBytes !== void 0 && downloaded > opts.maxBytes) throw new Error(`Downloaded ${downloaded} bytes exceeds the ${opts.maxBytes}-byte limit`);
|
|
73586
|
-
fileStream.write(value);
|
|
73587
|
-
opts.onProgress?.(downloaded, total);
|
|
73588
|
-
}
|
|
73589
|
-
} finally {
|
|
73590
|
-
fileStream.end();
|
|
73591
|
-
await new Promise((resolve, reject) => {
|
|
73592
|
-
fileStream.on("finish", resolve);
|
|
73593
|
-
fileStream.on("error", reject);
|
|
73594
|
-
});
|
|
73595
|
-
}
|
|
73596
|
-
fs.renameSync(tmpPath, destPath);
|
|
73597
|
-
return destPath;
|
|
73598
|
-
} catch (err) {
|
|
73599
|
-
try {
|
|
73600
|
-
fs.unlinkSync(tmpPath);
|
|
73601
|
-
} catch {}
|
|
73602
|
-
throw err;
|
|
73603
|
-
}
|
|
73604
|
-
}
|
|
73605
|
-
/** Compute the on-disk path for a given model + format, even when not yet downloaded. */
|
|
73606
|
-
function getModelFilePath(modelsDir, entry, format) {
|
|
73607
|
-
const formatEntry = entry.formats[format];
|
|
73608
|
-
if (!formatEntry) return null;
|
|
73609
|
-
const filename = formatEntry.url.split("/").pop() ?? `${entry.id}.${format}`;
|
|
73610
|
-
return path$1.join(modelsDir, filename);
|
|
73611
|
-
}
|
|
73612
|
-
/** True iff the model file (or `Manifest.json` for directory bundles) exists and is non-empty. */
|
|
73613
|
-
function isModelDownloaded(modelsDir, entry, format) {
|
|
73614
|
-
const formatEntry = entry.formats[format];
|
|
73615
|
-
if (!formatEntry) return false;
|
|
73616
|
-
const modelPath = getModelFilePath(modelsDir, entry, format);
|
|
73617
|
-
if (!modelPath || !fs.existsSync(modelPath)) return false;
|
|
73618
|
-
if (formatEntry.isDirectory) return fs.existsSync(path$1.join(modelPath, "Manifest.json"));
|
|
73619
|
-
if (fs.statSync(modelPath).size <= 0) return false;
|
|
73620
|
-
return siblingFilesFor(formatEntry).every((f) => isNonEmptyFile(path$1.join(modelsDir, f)));
|
|
73621
|
-
}
|
|
73622
|
-
/** Remove the on-disk model file/directory. Returns true if something was deleted. */
|
|
73623
|
-
function deleteModelFromDisk(modelsDir, entry, format) {
|
|
73624
|
-
const modelPath = getModelFilePath(modelsDir, entry, format);
|
|
73625
|
-
if (!modelPath || !fs.existsSync(modelPath)) return false;
|
|
73626
|
-
const formatEntry = entry.formats[format];
|
|
73627
|
-
if (formatEntry?.isDirectory) fs.rmSync(modelPath, {
|
|
73628
|
-
recursive: true,
|
|
73629
|
-
force: true
|
|
73630
|
-
});
|
|
73631
|
-
else {
|
|
73632
|
-
fs.unlinkSync(modelPath);
|
|
73633
|
-
if (formatEntry) for (const sibling of siblingFilesFor(formatEntry)) {
|
|
73634
|
-
const sibPath = path$1.join(modelsDir, sibling);
|
|
73635
|
-
if (fs.existsSync(sibPath)) fs.unlinkSync(sibPath);
|
|
73636
|
-
}
|
|
73637
|
-
}
|
|
73638
|
-
return true;
|
|
73639
|
-
}
|
|
73640
|
-
promisify(brotliCompress);
|
|
73641
|
-
promisify(gzip);
|
|
73642
|
-
//#endregion
|
|
73643
73500
|
//#region src/runtime/model-ops.ts
|
|
73644
73501
|
/**
|
|
73645
73502
|
* Default `RuntimeModelOps` — the ONLY place the reused object-detection model
|
|
@@ -73675,14 +73532,14 @@ function planFiles(modelsDir, entry) {
|
|
|
73675
73532
|
const filename = formatEntry.url.split("/").pop() ?? `${entry.id}.${GGUF}`;
|
|
73676
73533
|
out.push({
|
|
73677
73534
|
url: formatEntry.url,
|
|
73678
|
-
destPath: path
|
|
73535
|
+
destPath: path.join(modelsDir, filename),
|
|
73679
73536
|
filename,
|
|
73680
73537
|
expectedBytes: formatEntry.sizeMB * BYTES_PER_MB
|
|
73681
73538
|
});
|
|
73682
73539
|
}
|
|
73683
73540
|
for (const extra of entry.extraFiles ?? []) out.push({
|
|
73684
73541
|
url: extra.url,
|
|
73685
|
-
destPath: path
|
|
73542
|
+
destPath: path.join(modelsDir, extra.filename),
|
|
73686
73543
|
filename: extra.filename,
|
|
73687
73544
|
expectedBytes: extra.sizeMB * BYTES_PER_MB
|
|
73688
73545
|
});
|
|
@@ -73727,7 +73584,7 @@ function createDefaultModelOps(modelsDir) {
|
|
|
73727
73584
|
delete: async (entry) => {
|
|
73728
73585
|
deleteModelFromDisk(modelsDir, entry, GGUF);
|
|
73729
73586
|
},
|
|
73730
|
-
extraFilePath: (_entry, filename) => path
|
|
73587
|
+
extraFilePath: (_entry, filename) => path.join(modelsDir, filename)
|
|
73731
73588
|
};
|
|
73732
73589
|
}
|
|
73733
73590
|
//#endregion
|
|
@@ -74437,7 +74294,7 @@ function createLlmRuntimeProvider(deps) {
|
|
|
74437
74294
|
deleteModel: async ({ file }) => {
|
|
74438
74295
|
const loaded = deps.supervisor.status().modelPath;
|
|
74439
74296
|
if (loaded !== void 0 && basename(loaded) === file) throw new Error(`cannot delete ${file}: loaded by the running runtime`);
|
|
74440
|
-
await fsp.rm(path
|
|
74297
|
+
await fsp.rm(path.join(deps.modelsDir, file), { force: true });
|
|
74441
74298
|
},
|
|
74442
74299
|
listLocalModels: async () => {
|
|
74443
74300
|
return (await listGgufFiles(deps.modelsDir)).map((f) => {
|
|
@@ -74445,7 +74302,7 @@ function createLlmRuntimeProvider(deps) {
|
|
|
74445
74302
|
return {
|
|
74446
74303
|
file: f.file,
|
|
74447
74304
|
sizeBytes: f.sizeBytes,
|
|
74448
|
-
path: path
|
|
74305
|
+
path: path.join(deps.modelsDir, f.file),
|
|
74449
74306
|
...catalogId !== void 0 ? { catalogId } : {}
|
|
74450
74307
|
};
|
|
74451
74308
|
});
|
|
@@ -74470,7 +74327,7 @@ async function listGgufFiles(dir) {
|
|
|
74470
74327
|
for (const name of names) {
|
|
74471
74328
|
if (!name.endsWith(".gguf")) continue;
|
|
74472
74329
|
try {
|
|
74473
|
-
const stat = await fsp.stat(path
|
|
74330
|
+
const stat = await fsp.stat(path.join(dir, name));
|
|
74474
74331
|
out.push({
|
|
74475
74332
|
file: name,
|
|
74476
74333
|
sizeBytes: stat.size
|
|
@@ -75804,7 +75661,7 @@ var AiAddon = class extends BaseAddon {
|
|
|
75804
75661
|
this.supervisor = supervisor;
|
|
75805
75662
|
const settingsPort = api !== void 0 ? createApiSettingsStorePort(api) : createMemorySettingsStorePort();
|
|
75806
75663
|
if (api === void 0) logger.warn("addon-ai: no ctx.api — profiles are in-memory only");
|
|
75807
|
-
const binDir = path
|
|
75664
|
+
const binDir = path.join(ctx.nodeDataDir, "bin");
|
|
75808
75665
|
const { ensureLlamaServer } = await import("./ensure-llama-server-D_uzfSep.mjs").then((n) => n.r);
|
|
75809
75666
|
const assembly = await assembleAi({
|
|
75810
75667
|
nodeId: ownNodeId,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@camstack/addon-ai",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.30",
|
|
4
4
|
"description": "AI addon for CamStack — the `llm` collection provider (cloud, LAN, and camstack-managed local llama.cpp profiles) plus the per-node `llm-runtime` managed executor.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"camstack",
|