locale-ai 0.6.9 → 0.6.10
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/README.md +1 -1
- package/dist/catalog.js +13 -0
- package/dist/models.js +20 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -105,7 +105,7 @@ then declare it in `locale-ai.config.json`:
|
|
|
105
105
|
}
|
|
106
106
|
```
|
|
107
107
|
|
|
108
|
-
- `path` is a local folder (relative to the config file); `repo` is a Hugging Face repo with the converted files (uploaded output folder), downloaded and cached like built-in models.
|
|
108
|
+
- `path` is a local folder (relative to the config file); `repo` is a Hugging Face repo with the converted files (uploaded output folder), downloaded and cached like built-in models — it must look like `namespace/name`, rejected otherwise (it's joined onto the cache directory with no further checks, so anything else could resolve outside it).
|
|
109
109
|
- `prefix` is required for multi-target models (`convert` lists the model's `>>xx<<` tokens).
|
|
110
110
|
- Project models take priority over built-ins for their language pairs and can be used for pivoting (e.g. `ja → en → tr`).
|
|
111
111
|
|
package/dist/catalog.js
CHANGED
|
@@ -90,10 +90,23 @@ export const CATALOG = [
|
|
|
90
90
|
},
|
|
91
91
|
];
|
|
92
92
|
const asList = (v) => (Array.isArray(v) ? v : [v]).map((x) => parseLocale(x).lang);
|
|
93
|
+
/**
|
|
94
|
+
* A Hugging Face repo id is always exactly "namespace/name". `models.ts` joins it
|
|
95
|
+
* onto the cache root with no further checks, so a `repo` of "../../../etc" (or any
|
|
96
|
+
* segment that isn't a real name) would resolve outside the cache directory — and
|
|
97
|
+
* install() writes there, uninstall() recursively deletes there.
|
|
98
|
+
*/
|
|
99
|
+
function validRepo(repo) {
|
|
100
|
+
const parts = repo.split("/");
|
|
101
|
+
return parts.length === 2 && parts.every((p) => p !== "" && p !== "." && p !== ".." && !p.includes("\\"));
|
|
102
|
+
}
|
|
93
103
|
export function customEntries(models, configDir) {
|
|
94
104
|
return (models ?? []).map((c, i) => {
|
|
95
105
|
if (!c.repo === !c.path)
|
|
96
106
|
throw new Error(`models[${i}]: set exactly one of "repo" or "path".`);
|
|
107
|
+
if (c.repo && !validRepo(c.repo)) {
|
|
108
|
+
throw new Error(`models[${i}]: "repo" must look like "namespace/name" (a Hugging Face repo id), got "${c.repo}".`);
|
|
109
|
+
}
|
|
97
110
|
if (!c.source || !c.target)
|
|
98
111
|
throw new Error(`models[${i}]: "source" and "target" are required.`);
|
|
99
112
|
const sources = asList(c.source);
|
package/dist/models.js
CHANGED
|
@@ -25,8 +25,26 @@ export function cacheRoot() {
|
|
|
25
25
|
return path.join(process.env.XDG_CACHE_HOME || path.join(os.homedir(), ".cache"), "locale-ai");
|
|
26
26
|
}
|
|
27
27
|
const modelsRoot = () => path.join(cacheRoot(), "models");
|
|
28
|
-
/**
|
|
29
|
-
|
|
28
|
+
/**
|
|
29
|
+
* Where a model's files live: its local folder, or its cache folder. `repo` is
|
|
30
|
+
* validated as a plain "namespace/name" Hugging Face id when it comes from a
|
|
31
|
+
* project config (see catalog.ts's customEntries) — this is a second,
|
|
32
|
+
* independent check that the computed cache folder actually stays inside the
|
|
33
|
+
* cache root, since install() writes there and uninstall() recursively deletes
|
|
34
|
+
* it: a `repo` that somehow smuggled a ".." segment past that first check must
|
|
35
|
+
* never be allowed to touch a path outside the cache.
|
|
36
|
+
*/
|
|
37
|
+
export function modelDir(m) {
|
|
38
|
+
if (m.path)
|
|
39
|
+
return m.path;
|
|
40
|
+
const root = modelsRoot();
|
|
41
|
+
const dir = path.join(root, ...m.repo.split("/"));
|
|
42
|
+
const rel = path.relative(root, dir);
|
|
43
|
+
if (rel.startsWith("..") || path.isAbsolute(rel)) {
|
|
44
|
+
throw new Error(`${m.id}: "repo" (${m.repo}) resolves outside the model cache.`);
|
|
45
|
+
}
|
|
46
|
+
return dir;
|
|
47
|
+
}
|
|
30
48
|
export function readManifest(m) {
|
|
31
49
|
if (m.path)
|
|
32
50
|
return undefined;
|