* Cache a marketplace from a URL * * Downloads a marketplace.json file from a URL and saves it locally. * Creates the cache directory structure if it doesn't exist. * * Example marketplace.json structure: * ```json * { * "name": "my-marketplace", * "owner": { "name": "John Doe", "email"
( url: string, cachePath: string, customHeaders?: Record<string, string>, onProgress?: MarketplaceProgressCallback, )
| 1254 | * @param onProgress - Optional callback to report progress |
| 1255 | */ |
| 1256 | async function cacheMarketplaceFromUrl( |
| 1257 | url: string, |
| 1258 | cachePath: string, |
| 1259 | customHeaders?: Record<string, string>, |
| 1260 | onProgress?: MarketplaceProgressCallback, |
| 1261 | ): Promise<void> { |
| 1262 | const fs = getFsImplementation() |
| 1263 | |
| 1264 | const redactedUrl = redactUrlCredentials(url) |
| 1265 | safeCallProgress(onProgress, `Downloading marketplace from ${redactedUrl}`) |
| 1266 | logForDebugging(`Downloading marketplace from URL: ${redactedUrl}`) |
| 1267 | if (customHeaders && Object.keys(customHeaders).length > 0) { |
| 1268 | logForDebugging( |
| 1269 | `Using custom headers: ${jsonStringify(redactHeaders(customHeaders))}`, |
| 1270 | ) |
| 1271 | } |
| 1272 | |
| 1273 | const headers = { |
| 1274 | ...customHeaders, |
| 1275 | // User-Agent must come last to prevent override (for consistency with WebFetch) |
| 1276 | 'User-Agent': 'Claude-Code-Plugin-Manager', |
| 1277 | } |
| 1278 | |
| 1279 | let response |
| 1280 | const fetchStarted = performance.now() |
| 1281 | try { |
| 1282 | response = await axios.get(url, { |
| 1283 | timeout: 10000, |
| 1284 | headers, |
| 1285 | }) |
| 1286 | } catch (error) { |
| 1287 | logPluginFetch( |
| 1288 | 'marketplace_url', |
| 1289 | url, |
| 1290 | 'failure', |
| 1291 | performance.now() - fetchStarted, |
| 1292 | classifyFetchError(error), |
| 1293 | ) |
| 1294 | if (axios.isAxiosError(error)) { |
| 1295 | if (error.code === 'ECONNREFUSED' || error.code === 'ENOTFOUND') { |
| 1296 | throw new Error( |
| 1297 | `Could not connect to ${redactedUrl}. Please check your internet connection and verify the URL is correct.\n\nTechnical details: ${error.message}`, |
| 1298 | ) |
| 1299 | } |
| 1300 | if (error.code === 'ETIMEDOUT') { |
| 1301 | throw new Error( |
| 1302 | `Request timed out while downloading marketplace from ${redactedUrl}. The server may be slow or unreachable.\n\nTechnical details: ${error.message}`, |
| 1303 | ) |
| 1304 | } |
| 1305 | if (error.response) { |
| 1306 | throw new Error( |
| 1307 | `HTTP ${error.response.status} error while downloading marketplace from ${redactedUrl}. The marketplace file may not exist at this URL.\n\nTechnical details: ${error.message}`, |
| 1308 | ) |
| 1309 | } |
| 1310 | } |
| 1311 | throw new Error( |
| 1312 | `Failed to download marketplace from ${redactedUrl}: ${errorMessage(error)}`, |
| 1313 | ) |
no test coverage detected