@remcostoeten/fync
Version:
A unified TypeScript library for easy access to popular APIs (GitHub, Spotify, GitLab, etc.)
313 lines • 12.9 kB
JavaScript
import { createNpmClient } from "./services/npm-client";
/**
* Creates a new NPM Registry API client
*
* @param config - Optional configuration for the NPM client
* @param config.cache - Enable response caching (default: false)
* @param config.cacheTTL - Cache time-to-live in milliseconds (default: 300000)
* @param config.baseUrl - Custom NPM registry URL (default: https://registry.npmjs.org)
* @param config.timeout - Request timeout in milliseconds (default: 30000)
*
* @returns NPM client instance with access to packages, search, downloads, users, orgs, and tags
*
* @example
* ```typescript
* const npm = NPM({ cache: true, cacheTTL: 600000 });
*
* // Get package information
* const reactInfo = await npm.package('react').get();
*
* // Search for packages
* const results = await npm.search.packages('typescript');
*
* // Get download statistics
* const downloads = await npm.downloads.package('react', 'last-week');
* ```
*/
function NPM(config) {
const client = createNpmClient(config);
function createPackageClient(packageName) {
const packageBase = client[encodeURIComponent(packageName)];
return {
get: () => packageBase.get(),
version: (version) => createVersionClient(packageName, version),
latest: async () => {
const packageInfo = await packageBase.get();
const latestVersion = packageInfo["dist-tags"]?.latest;
if (!latestVersion) {
throw new Error(`No latest version found for ${packageName}`);
}
return packageInfo.versions[latestVersion];
},
versions: async () => {
const packageInfo = await packageBase.get();
return packageInfo.versions;
},
downloads: {
last: (period) => client.downloads.point[`last-${period}`][encodeURIComponent(packageName)].get(),
range: (start, end) => client.downloads.range[`${start}:${end}`][encodeURIComponent(packageName)].get(),
},
// Advanced features
vulnerabilities: async () => {
// Use npm audit API (hypothetical endpoint)
try {
const auditClient = createNpmClient({
...config,
baseUrl: "https://registry.npmjs.org/-/npm/v1/security",
});
return await auditClient.advisories[packageName].get();
}
catch {
return [];
}
},
audit: async () => {
// Use npm audit API
const auditClient = createNpmClient({
...config,
baseUrl: "https://registry.npmjs.org/-/npm/v1/security",
});
return await auditClient.audits.quick[packageName].get();
},
size: async () => {
// Get package size info (bundlephobia-like data)
const packageInfo = await packageBase.get();
const latestVersion = packageInfo["dist-tags"]?.latest;
if (!latestVersion) {
throw new Error(`No latest version found for ${packageName}`);
}
// Calculate size from dist info
const version = packageInfo.versions[latestVersion];
const files = version.files?.length || 0;
return {
size: 0, // Would need external service
gzip: 0, // Would need external service
files,
};
},
deprecation: async () => {
const packageInfo = await packageBase.get();
// Check for deprecated versions
const deprecatedVersions = [];
for (const [version, versionInfo] of Object.entries(packageInfo.versions)) {
if ("deprecated" in versionInfo && versionInfo.deprecated) {
deprecatedVersions.push(version);
}
}
if (deprecatedVersions.length === 0) {
return null;
}
return {
versions: deprecatedVersions,
message: "Package has deprecated versions",
time: new Date().toISOString(),
};
},
distTags: async () => {
const packageInfo = await packageBase.get();
return packageInfo["dist-tags"];
},
collaborators: async () => {
// Get package maintainers/collaborators
const packageInfo = await packageBase.get();
return packageInfo.maintainers.map((maintainer) => ({
name: maintainer.name,
email: maintainer.email,
access: "write",
}));
},
isDeprecated: async () => {
const packageInfo = await packageBase.get();
const latestVersion = packageInfo["dist-tags"]?.latest;
if (!latestVersion)
return false;
const version = packageInfo.versions[latestVersion];
return !!("deprecated" in version && version.deprecated);
},
bundleAnalysis: async () => {
// Get bundle analysis (would integrate with bundlephobia API)
const packageInfo = await packageBase.get();
const latestVersion = packageInfo["dist-tags"]?.latest;
if (!latestVersion) {
throw new Error(`No latest version found for ${packageName}`);
}
const version = packageInfo.versions[latestVersion];
const dependencies = Object.keys(version.dependencies || {});
return {
size: 0, // Would need bundlephobia integration
gzip: 0, // Would need bundlephobia integration
modules: dependencies.length,
dependencies,
};
},
chain: packageBase,
};
}
function createVersionClient(packageName, version) {
const versionBase = client[encodeURIComponent(packageName)][version];
return {
get: () => versionBase.get(),
chain: versionBase,
};
}
const searchClient = {
packages: (query, options) => {
const params = {
text: query,
...options?.params,
};
if (options?.size)
params.size = options.size;
if (options?.from)
params.from = options.from;
if (options?.quality)
params.quality = options.quality;
if (options?.popularity)
params.popularity = options.popularity;
if (options?.maintenance)
params.maintenance = options.maintenance;
// NPM search uses different base URL
const searchClient = createNpmClient({
...config,
baseUrl: "https://registry.npmjs.org/-/v1",
});
return searchClient.search.get({
...options,
params,
});
},
chain: client["-"].v1.search,
};
const downloadsClient = {
package: (packageName, period = "last-week") => {
// NPM downloads API uses different base URL
const downloadsApiClient = createNpmClient({
...config,
baseUrl: "https://api.npmjs.org",
});
return downloadsApiClient.downloads.point[period][encodeURIComponent(packageName)].get();
},
packages: async (packageNames, period = "last-week") => {
const downloadsApiClient = createNpmClient({
...config,
baseUrl: "https://api.npmjs.org",
});
const packageList = packageNames.map(encodeURIComponent).join(",");
const response = await downloadsApiClient.downloads.point[period][packageList].get();
return response;
},
range: (packageName, start, end) => {
const downloadsApiClient = createNpmClient({
...config,
baseUrl: "https://api.npmjs.org",
});
return downloadsApiClient.downloads.range[`${start}:${end}`][encodeURIComponent(packageName)].get();
},
chain: createNpmClient({
...config,
baseUrl: "https://api.npmjs.org",
}).downloads,
};
function createUserClient(username) {
// NPM user API uses different base URL
const npmApiClient = createNpmClient({
...config,
baseUrl: "https://registry.npmjs.org/-/user",
});
const userBase = npmApiClient[username];
return {
get: () => userBase.get(),
packages: async (options) => {
// Search packages by author
const searchClient = createNpmClient({
...config,
baseUrl: "https://registry.npmjs.org/-/v1",
});
const searchResults = await searchClient.search.get({
...options,
params: {
text: `author:${username}`,
size: 250,
...options?.params,
},
});
// Convert search results to package info
const packages = await Promise.all(searchResults.objects.map((result) => client[encodeURIComponent(result.package.name)].get()));
return packages;
},
chain: userBase,
};
}
function createOrgClient(orgName) {
// NPM org API uses different base URL
const npmApiClient = createNpmClient({
...config,
baseUrl: "https://registry.npmjs.org/-/org",
});
const orgBase = npmApiClient[orgName];
return {
get: () => orgBase.get(),
packages: async (options) => {
// Search packages by scope
const searchClient = createNpmClient({
...config,
baseUrl: "https://registry.npmjs.org/-/v1",
});
const searchResults = await searchClient.search.get({
...options,
params: {
text: `scope:${orgName}`,
size: 250,
...options?.params,
},
});
// Convert search results to package info
const packages = await Promise.all(searchResults.objects.map((result) => client[encodeURIComponent(result.package.name)].get()));
return packages;
},
members: async (options) => {
// Get organization members
const membersResponse = await orgBase.users.get(options);
// Convert to user objects
const usernames = Object.keys(membersResponse);
const users = await Promise.all(usernames.map((username) => createUserClient(username).get()));
return users;
},
chain: orgBase,
};
}
function createTagClient(tag) {
return {
packages: async (options) => {
// Search packages by keyword/tag
const searchClient = createNpmClient({
...config,
baseUrl: "https://registry.npmjs.org/-/v1",
});
const searchResults = await searchClient.search.get({
...options,
params: {
text: `keywords:${tag}`,
size: 250,
...options?.params,
},
});
// Convert search results to package info
const packages = await Promise.all(searchResults.objects.map((result) => client[encodeURIComponent(result.package.name)].get()));
return packages;
},
chain: client,
};
}
return {
api: client,
package: createPackageClient,
search: searchClient,
downloads: downloadsClient,
user: createUserClient,
org: createOrgClient,
tag: createTagClient,
};
}
export { NPM };
//# sourceMappingURL=index.js.map