npx-scope-finder
Version:
A tool to find executable (npx-compatible) packages within a specific npm scope
1 lines • 2.43 kB
JavaScript
import e from"p-limit";var t=class extends Error{retryAfter;constructor(e,t){super(e),this.retryAfter=t}};async function n(e,n={}){let{timeout:i=1e4,retries:a=3,retryDelay:o=1e3}=n,s=null;for(let n=0;n<=a;n++)try{let n=new AbortController,a=setTimeout(()=>n.abort(),i),o=await fetch(e,{signal:n.signal,headers:{Accept:`application/json`}});if(clearTimeout(a),!o.ok){let e=o.status===429?r(o.headers.get(`Retry-After`)):void 0;throw new t(`HTTP error! status: ${o.status}`,e)}return await o.json()}catch(e){if(s=e,n<a){let r=o*2**n,i=e instanceof t&&e.retryAfter!=null&&e.retryAfter>0?Math.max(e.retryAfter*1e3,r):r;await new Promise(e=>setTimeout(e,i))}}throw s}function r(e){if(e==null)return;let t=Number(e);return Number.isFinite(t)?t:void 0}function i(e,t,n){return{name:e,description:t.description,version:t.version,bin:t.bin,dependencies:t.dependencies,scripts:t.scripts,keywords:t.keywords,links:{npm:`https://www.npmjs.com/package/${e}`,repository:t.repository?.url?.replace(/^git\+/,``).replace(/\.git$/,``),homepage:t.homepage},original:n}}async function a(t,r={}){if(!t.startsWith(`@`))throw Error(`Scope must start with "@"`);let{concurrency:a=10,maxPages:s=5,includeOriginal:c=!1,logger:l}=r,u=e(a),d=[],f=0;for(let e=0;e<s;e++){let e=await n(`https://registry.npmjs.org/-/v1/search?text=${encodeURIComponent(t)}&size=250&from=${f}`,r);if(!e.objects||!Array.isArray(e.objects))throw Error(`Invalid search response format`);let i=e.objects.filter(e=>e.package.name.startsWith(t)).map(e=>e.package.name);if(d.push(...i),f+=e.objects.length,f>=e.total||e.objects.length<250)break}if(d.length===0)return[];let p=d.map(e=>u(async()=>c?{packageName:e,packageInfo:await n(`https://registry.npmjs.org/${encodeURIComponent(e)}`,r),isFullMetadata:!0}:{packageName:e,versionInfo:await n(`https://registry.npmjs.org/${encodeURIComponent(e)}/latest`,r),isFullMetadata:!1})),m=await Promise.allSettled(p),h=[];for(let e of m){if(e.status===`rejected`){l?.error(`Error fetching package details:`,e.reason);continue}let t=e.value;if(t.isFullMetadata){let{packageName:e,packageInfo:n}=t;if(!n[`dist-tags`]||!n.versions){l?.error(`Invalid package info format:`,e);continue}let r=n[`dist-tags`].latest,a=n.versions[r];o(a)&&h.push(i(e,a,n))}else{let{packageName:e,versionInfo:n}=t;if(!n||!n.version){l?.error(`Invalid package info format:`,e);continue}o(n)&&h.push(i(e,n))}}return h}function o(e){return!!e.bin}export{a as npxFinder};