npx-scope-finder
Version:
A tool to find executable (npx-compatible) packages within a specific npm scope
1 lines • 1.82 kB
JavaScript
;async function fetchWithRetry(e,t={}){const{timeout:r=1e4,retries:o=3,retryDelay:n=1e3}=t;let s=null;for(let t=0;t<=o;t++)try{const t=new AbortController,o=setTimeout((()=>t.abort()),r),n=await fetch(e,{signal:t.signal,headers:{Accept:"application/json"}});if(clearTimeout(o),!n.ok)throw new Error(`HTTP error! status: ${n.status}`);return await n.json()}catch(e){s=e,t<o&&await new Promise((e=>setTimeout(e,n)))}throw s}async function npxFinder(e,t={}){if(!e.startsWith("@"))throw new Error('Scope must start with "@"');try{const r=`https://registry.npmjs.org/-/v1/search?text=${encodeURIComponent(e)}`,o=await fetchWithRetry(r,t);if(!o.objects||!Array.isArray(o.objects))throw new Error("Invalid search response format");const n=o.objects.filter((t=>t.package.name.startsWith(e))).map((e=>e.package.name));if(0===n.length)return[];const s=n.map((e=>fetchWithRetry(`https://registry.npmjs.org/${encodeURIComponent(e)}`,t).then((t=>({packageName:e,packageInfo:t}))))),a=await Promise.allSettled(s),i=[];for(const e of a){if("rejected"===e.status){console.error("Error fetching package details:",e.reason);continue}const{packageName:t,packageInfo:r}=e.value,o=r;if(!o["dist-tags"]||!o.versions){console.error("Invalid package info format:",t);continue}const n=o["dist-tags"].latest,s=o.versions[n];isExecutablePackage(s)&&i.push({name:t,description:s.description,version:n,bin:s.bin,dependencies:s.dependencies,scripts:s.scripts,keywords:s.keywords,links:{npm:`https://www.npmjs.com/package/${t}`,repository:s.repository?.url?.replace(/^git\+/,"").replace(/\.git$/,""),homepage:s.homepage},original:o})}return i}catch(e){throw console.error("Error fetching npm packages:",e),e}}function isExecutablePackage(e){return!!e.bin}Object.defineProperty(exports,"__esModule",{value:!0}),exports.npxFinder=npxFinder;