/** * Plugin cache path construction + containment checks (pure). * * Installed plugin files live in `/cache////` * with every segment sanitized — marketplace manifests are third-party content, * so entry names must never be able to place files outside the cache, and * `./relative` plugin sources must never read outside their marketplace clone. */ import { join } from "node:path"; import { pathWithinBase, sanitizePathSegment } from "../../lib/plugin-root.ts"; /** The directory holding every version of one plugin: `/cache//`. */ export function pluginCacheDir(root: string, marketplace: string, plugin: string): string { return join(root, "cache", sanitizePathSegment(marketplace), sanitizePathSegment(plugin)); } export function versionedCachePath(root: string, marketplace: string, plugin: string, version: string): string { return join(pluginCacheDir(root, marketplace, plugin), sanitizePathSegment(version, true)); } /** True when `target` resolves inside `base` (rejects .. escapes and absolute overrides). */ export const withinBase = pathWithinBase;