@hyperframes/parsers 0.7.81 → 0.7.83
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/ffBinaries.d.ts +3 -2
- package/dist/ffBinaries.js +19 -12
- package/dist/ffBinaries.js.map +1 -1
- package/package.json +2 -2
package/dist/ffBinaries.d.ts
CHANGED
|
@@ -17,8 +17,9 @@ interface FindFfBinaryOptions {
|
|
|
17
17
|
configuredMustExist?: boolean;
|
|
18
18
|
}
|
|
19
19
|
/**
|
|
20
|
-
* Resolve an FFmpeg-family binary: env override first, then
|
|
21
|
-
*
|
|
20
|
+
* Resolve an FFmpeg-family binary: env override first, then a native
|
|
21
|
+
* current-directory/PATH scan on Windows or `which` plus PATH scan on Unix,
|
|
22
|
+
* then a project-local
|
|
22
23
|
* `.hyperframes/bin`, then well-known Unix install dirs. System lookups are
|
|
23
24
|
* cached per binary for the process lifetime; the env override is re-read on
|
|
24
25
|
* every call.
|
package/dist/ffBinaries.js
CHANGED
|
@@ -27,7 +27,11 @@ function isExecutablePathCandidate(candidate) {
|
|
|
27
27
|
}
|
|
28
28
|
function scanPath(name) {
|
|
29
29
|
const pathValue = process.env.PATH;
|
|
30
|
-
|
|
30
|
+
const searchDirs = [
|
|
31
|
+
...process.platform === "win32" ? [process.cwd()] : [],
|
|
32
|
+
...pathValue ? pathValue.split(delimiter) : []
|
|
33
|
+
].filter(Boolean);
|
|
34
|
+
if (searchDirs.length === 0) return void 0;
|
|
31
35
|
const extensions = process.platform === "win32" ? [
|
|
32
36
|
".exe",
|
|
33
37
|
...new Set(
|
|
@@ -36,8 +40,7 @@ function scanPath(name) {
|
|
|
36
40
|
""
|
|
37
41
|
] : [""];
|
|
38
42
|
const candidates = [];
|
|
39
|
-
for (const dir of
|
|
40
|
-
if (!dir) continue;
|
|
43
|
+
for (const dir of new Set(searchDirs)) {
|
|
41
44
|
for (const ext of extensions) {
|
|
42
45
|
const candidate = join(dir, `${name}${ext}`);
|
|
43
46
|
if (isExecutablePathCandidate(candidate)) candidates.push(candidate);
|
|
@@ -61,16 +64,20 @@ function findInProjectLocalBin(name) {
|
|
|
61
64
|
function lookupOnSystem(name) {
|
|
62
65
|
if (pathLookupCache.has(name)) return pathLookupCache.get(name);
|
|
63
66
|
let found;
|
|
64
|
-
|
|
65
|
-
const command = process.platform === "win32" ? "where" : "which";
|
|
66
|
-
const output = execFileSync(command, [name], {
|
|
67
|
-
encoding: "utf-8",
|
|
68
|
-
stdio: ["pipe", "pipe", "pipe"],
|
|
69
|
-
timeout: 5e3
|
|
70
|
-
});
|
|
71
|
-
found = chooseBestPathCandidate(name, output.split(/\r?\n/));
|
|
72
|
-
} catch {
|
|
67
|
+
if (process.platform === "win32") {
|
|
73
68
|
found = scanPath(name);
|
|
69
|
+
} else {
|
|
70
|
+
try {
|
|
71
|
+
const output = execFileSync("which", [name], {
|
|
72
|
+
encoding: "utf-8",
|
|
73
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
74
|
+
timeout: 5e3
|
|
75
|
+
});
|
|
76
|
+
const candidate = chooseBestPathCandidate(name, output.split(/\r?\n/));
|
|
77
|
+
found = candidate && isExecutablePathCandidate(candidate) ? candidate : scanPath(name);
|
|
78
|
+
} catch {
|
|
79
|
+
found = scanPath(name);
|
|
80
|
+
}
|
|
74
81
|
}
|
|
75
82
|
found ??= findInProjectLocalBin(name);
|
|
76
83
|
found ??= findInCommonDirs(name);
|
package/dist/ffBinaries.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/ffBinaries.ts"],"sourcesContent":["import { execFileSync } from \"node:child_process\";\nimport { accessSync, constants, existsSync } from \"node:fs\";\nimport { delimiter, join, resolve } from \"node:path\";\n\n/**\n * Shared FFmpeg/FFprobe binary resolution for every package that shells out\n * to them (engine, cli, lint, studio-server). Node-only: import via the\n * `@hyperframes/parsers/ff-binaries` subpath, never from a browser bundle.\n */\n\nexport const FFMPEG_PATH_ENV = \"HYPERFRAMES_FFMPEG_PATH\";\nexport const FFPROBE_PATH_ENV = \"HYPERFRAMES_FFPROBE_PATH\";\n\nexport type FfBinaryName = \"ffmpeg\" | \"ffprobe\";\n\nconst ENV_BY_NAME: Record<FfBinaryName, string> = {\n ffmpeg: FFMPEG_PATH_ENV,\n ffprobe: FFPROBE_PATH_ENV,\n};\n\nconst pathLookupCache = new Map<FfBinaryName, string | undefined>();\n\nfunction candidateFileName(candidate: string): string {\n return candidate.split(/[\\\\/]/).at(-1)?.toLowerCase() ?? candidate.toLowerCase();\n}\n\nfunction chooseBestPathCandidate(\n name: FfBinaryName,\n candidates: readonly string[],\n): string | undefined {\n const normalized = candidates.map((candidate) => candidate.trim()).filter(Boolean);\n return (\n normalized.find((candidate) => candidateFileName(candidate) === `${name}.exe`) ??\n normalized.find((candidate) => candidateFileName(candidate) === name) ??\n normalized.find((candidate) => !candidateFileName(candidate).match(/\\.(cmd|bat)$/i)) ??\n normalized[0]\n );\n}\n\nfunction isExecutablePathCandidate(candidate: string): boolean {\n if (process.platform === \"win32\") return existsSync(candidate);\n try {\n accessSync(candidate, constants.X_OK);\n return true;\n } catch {\n return false;\n }\n}\n\nfunction scanPath(name: FfBinaryName): string | undefined {\n const pathValue = process.env.PATH;\n
|
|
1
|
+
{"version":3,"sources":["../src/ffBinaries.ts"],"sourcesContent":["import { execFileSync } from \"node:child_process\";\nimport { accessSync, constants, existsSync } from \"node:fs\";\nimport { delimiter, join, resolve } from \"node:path\";\n\n/**\n * Shared FFmpeg/FFprobe binary resolution for every package that shells out\n * to them (engine, cli, lint, studio-server). Node-only: import via the\n * `@hyperframes/parsers/ff-binaries` subpath, never from a browser bundle.\n */\n\nexport const FFMPEG_PATH_ENV = \"HYPERFRAMES_FFMPEG_PATH\";\nexport const FFPROBE_PATH_ENV = \"HYPERFRAMES_FFPROBE_PATH\";\n\nexport type FfBinaryName = \"ffmpeg\" | \"ffprobe\";\n\nconst ENV_BY_NAME: Record<FfBinaryName, string> = {\n ffmpeg: FFMPEG_PATH_ENV,\n ffprobe: FFPROBE_PATH_ENV,\n};\n\nconst pathLookupCache = new Map<FfBinaryName, string | undefined>();\n\nfunction candidateFileName(candidate: string): string {\n return candidate.split(/[\\\\/]/).at(-1)?.toLowerCase() ?? candidate.toLowerCase();\n}\n\nfunction chooseBestPathCandidate(\n name: FfBinaryName,\n candidates: readonly string[],\n): string | undefined {\n const normalized = candidates.map((candidate) => candidate.trim()).filter(Boolean);\n return (\n normalized.find((candidate) => candidateFileName(candidate) === `${name}.exe`) ??\n normalized.find((candidate) => candidateFileName(candidate) === name) ??\n normalized.find((candidate) => !candidateFileName(candidate).match(/\\.(cmd|bat)$/i)) ??\n normalized[0]\n );\n}\n\nfunction isExecutablePathCandidate(candidate: string): boolean {\n if (process.platform === \"win32\") return existsSync(candidate);\n try {\n accessSync(candidate, constants.X_OK);\n return true;\n } catch {\n return false;\n }\n}\n\nfunction scanPath(name: FfBinaryName): string | undefined {\n const pathValue = process.env.PATH;\n const searchDirs = [\n ...(process.platform === \"win32\" ? [process.cwd()] : []),\n ...(pathValue ? pathValue.split(delimiter) : []),\n ].filter(Boolean);\n if (searchDirs.length === 0) return undefined;\n\n const extensions =\n process.platform === \"win32\"\n ? [\n \".exe\",\n ...new Set(\n (process.env.PATHEXT ?? \".COM;.EXE;.BAT;.CMD\")\n .split(\";\")\n .map((ext) => ext.trim().toLowerCase())\n .filter(Boolean),\n ),\n \"\",\n ]\n : [\"\"];\n const candidates: string[] = [];\n for (const dir of new Set(searchDirs)) {\n for (const ext of extensions) {\n const candidate = join(dir, `${name}${ext}`);\n if (isExecutablePathCandidate(candidate)) candidates.push(candidate);\n }\n }\n return chooseBestPathCandidate(name, candidates);\n}\n\n// GUI/Dock/launchd-spawned processes on macOS don't inherit the shell PATH, so\n// `which ffmpeg` fails even when ffmpeg is installed via Homebrew. Probe the\n// well-known install dirs as a last resort. (No-op on Windows, where `where`\n// and installer-added PATH entries cover it.)\nconst COMMON_BIN_DIRS =\n process.platform === \"win32\"\n ? []\n : [\"/opt/homebrew/bin\", \"/usr/local/bin\", \"/usr/bin\", \"/bin\", \"/snap/bin\"];\n\nfunction findInCommonDirs(name: FfBinaryName): string | undefined {\n for (const dir of COMMON_BIN_DIRS) {\n const candidate = `${dir}/${name}`;\n if (existsSync(candidate)) return candidate;\n }\n return undefined;\n}\n\nfunction findInProjectLocalBin(name: FfBinaryName): string | undefined {\n const extension = process.platform === \"win32\" ? \".exe\" : \"\";\n const candidate = resolve(\".hyperframes\", \"bin\", `${name}${extension}`);\n return existsSync(candidate) ? candidate : undefined;\n}\n\nfunction lookupOnSystem(name: FfBinaryName): string | undefined {\n if (pathLookupCache.has(name)) return pathLookupCache.get(name);\n let found: string | undefined;\n if (process.platform === \"win32\") {\n // `where.exe` writes bytes in the active console code page, while Node\n // decodes its stdout using a caller-selected encoding. Enumerating the\n // same current-directory + PATH search space from Node keeps Unicode\n // paths as native JS strings and avoids mojibake entirely.\n found = scanPath(name);\n } else {\n try {\n const output = execFileSync(\"which\", [name], {\n encoding: \"utf-8\",\n stdio: [\"pipe\", \"pipe\", \"pipe\"],\n timeout: 5000,\n });\n const candidate = chooseBestPathCandidate(name, output.split(/\\r?\\n/));\n found = candidate && isExecutablePathCandidate(candidate) ? candidate : scanPath(name);\n } catch {\n found = scanPath(name);\n }\n }\n found ??= findInProjectLocalBin(name);\n found ??= findInCommonDirs(name);\n const resolved = found ? resolve(found) : undefined;\n pathLookupCache.set(name, resolved);\n return resolved;\n}\n\nexport interface FindFfBinaryOptions {\n /**\n * How to treat an env override that points at a missing file: `true`\n * reports the binary as not found (callers that surface an install hint or\n * skip probing), `false`/unset returns the configured path as-is (callers\n * that validate the override separately and want spawn errors to name the\n * path the user configured).\n */\n configuredMustExist?: boolean;\n}\n\n/**\n * Resolve an FFmpeg-family binary: env override first, then a native\n * current-directory/PATH scan on Windows or `which` plus PATH scan on Unix,\n * then a project-local\n * `.hyperframes/bin`, then well-known Unix install dirs. System lookups are\n * cached per binary for the process lifetime; the env override is re-read on\n * every call.\n */\nexport function findFfBinary(\n name: FfBinaryName,\n options: FindFfBinaryOptions = {},\n): string | undefined {\n const configured = process.env[ENV_BY_NAME[name]]?.trim();\n if (configured) {\n if (options.configuredMustExist && !existsSync(configured)) return undefined;\n return resolve(configured);\n }\n return lookupOnSystem(name);\n}\n\n/** Test hook: drop cached system lookups so resolution can be re-exercised. */\nexport function clearFfBinaryLookupCache(): void {\n pathLookupCache.clear();\n}\n"],"mappings":"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","names":[]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hyperframes/parsers",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.83",
|
|
4
4
|
"repository": {
|
|
5
5
|
"type": "git",
|
|
6
6
|
"url": "https://github.com/heygen-com/hyperframes",
|
|
@@ -98,7 +98,7 @@
|
|
|
98
98
|
"tsx": "^4.21.0",
|
|
99
99
|
"typescript": "^5.0.0",
|
|
100
100
|
"vitest": "^3.2.4",
|
|
101
|
-
"@hyperframes/core": "0.7.
|
|
101
|
+
"@hyperframes/core": "0.7.83"
|
|
102
102
|
},
|
|
103
103
|
"scripts": {
|
|
104
104
|
"build": "tsup",
|