verdaccio-plugin-community-nodes
Version:
plugin for n8n community nodes
147 lines • 6.99 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const semver_1 = __importDefault(require("semver"));
const PLUGIN_NAME = 'verdaccio-plugin-community-nodes';
const PLUGIN_VERSION = '0.2.6';
class VerdaccioMiddlewarePlugin {
config;
parsedConfig;
logger;
fetchOptions = {
headers: {
'User-Agent': `${PLUGIN_NAME}/${PLUGIN_VERSION}`
}
};
constructor(config, options) {
this.config = config;
this.logger = options.logger;
// Parse and validate configuration with defaults
const enabled = typeof config.enabled === 'string'
? config.enabled.toLowerCase() === 'true'
: !!config.enabled;
const environment = (config.environment || 'staging').toLowerCase();
// Determine API URL based on environment, but only if not provided in config
const apiUrl = this.config.apiUrl || (environment === 'production'
? 'https://api.n8n.io/api/community-nodes'
: 'https://api-staging.n8n.io/api/community-nodes');
this.parsedConfig = { ...config, enabled, environment, apiUrl };
this.logger.info(`${PLUGIN_NAME}@${PLUGIN_VERSION} initialized with config: ${JSON.stringify({
enabled: this.parsedConfig.enabled,
environment: this.parsedConfig.environment
})}`);
}
async filter_metadata(passedPackage) {
if (!this.parsedConfig.enabled) {
this.logger.debug(`${PLUGIN_NAME} is disabled, skipping filter_metadata for ${passedPackage.name}`);
return passedPackage;
}
try {
return await this.checkPackageVersions(passedPackage);
}
catch (error) {
if (error instanceof Error) {
this.logger.error(`${PLUGIN_NAME} error checking package ${passedPackage.name}: ${error.message}`);
}
else {
this.logger.error(`${PLUGIN_NAME} error checking package ${passedPackage.name}: ${String(error)}`);
}
return passedPackage;
}
}
async checkPackageVersions(passedPackage) {
const { name } = passedPackage;
try {
// Construct URL with proper encoding
const encodedPackageName = encodeURIComponent(name);
let url = `${this.parsedConfig.apiUrl}?filters[packageName][$eq]=${encodedPackageName}&filters[isPublished][$in][0]=true`;
// Add unpublished filter for staging environment
if (this.parsedConfig.environment === 'staging') {
url += '&filters[isPublished][$in][1]=false';
}
this.logger.debug(`${PLUGIN_NAME}: Fetching data for ${name} from ${url}`);
const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), 5000);
try {
const response = await fetch(url, {
...this.fetchOptions,
signal: controller.signal
});
if (!response.ok) {
const errorText = await response.text().catch(() => 'Unable to read error response');
throw new Error(`HTTP ${response.status}: ${errorText}`);
}
const data = await response.json();
// Validate response data
if (!data?.data?.length) {
this.logger.debug(`${PLUGIN_NAME}: No community node found for ${name}`);
return passedPackage;
}
const nodeData = data.data[0];
const nodeVersions = nodeData.attributes.nodeVersions;
if (!nodeVersions?.length) {
this.logger.debug(`${PLUGIN_NAME}: No versions found for ${name}`);
return passedPackage;
}
// Filter and sort approved versions using semver
const approvedVersions = [...nodeVersions]
.filter(v => semver_1.default.valid(v.npmVersion)) // Filter out invalid semver
.sort((a, b) => semver_1.default.compare(b.npmVersion, a.npmVersion));
if (!approvedVersions.length) {
this.logger.warn(`${PLUGIN_NAME}: No valid approved versions found for ${name}`);
return passedPackage;
}
// Filter to only versions that exist in the package
const availableApprovedVersions = approvedVersions.filter(v => passedPackage.versions && passedPackage.versions[v.npmVersion]);
if (!availableApprovedVersions.length) {
this.logger.warn(`${PLUGIN_NAME}: No approved versions are available in registry for ${name}`);
return passedPackage;
}
// Return package with only approved versions
const approvedVersionList = availableApprovedVersions.map(v => v.npmVersion).join(', ');
this.logger.debug(`${PLUGIN_NAME}: Filtering ${name} to only approved versions: ${approvedVersionList}`);
return this.createFilteredPackage(passedPackage, availableApprovedVersions);
}
finally {
clearTimeout(timeoutId);
}
}
catch (error) {
if (error instanceof Error) {
if (error.name === 'AbortError') {
this.logger.error(`${PLUGIN_NAME}: Request timeout for ${name}`);
}
else {
this.logger.error(`${PLUGIN_NAME}: API request failed for ${name}: ${error.message}`);
}
}
else {
this.logger.error(`${PLUGIN_NAME}: Unknown error for ${name}: ${String(error)}`);
}
throw error;
}
}
createFilteredPackage(pkg, approvedVersions) {
const modifiedPackage = { ...pkg };
// Only keep the approved versions
if (modifiedPackage.versions) {
const filteredVersions = {};
for (const approvedVersion of approvedVersions) {
const version = approvedVersion.npmVersion;
if (modifiedPackage.versions[version]) {
filteredVersions[version] = modifiedPackage.versions[version];
}
}
modifiedPackage.versions = filteredVersions;
// Update dist-tags to point to the newest approved version
if (modifiedPackage['dist-tags'] && approvedVersions.length > 0) {
modifiedPackage['dist-tags'].latest = approvedVersions[0].npmVersion;
}
}
return modifiedPackage;
}
}
exports.default = VerdaccioMiddlewarePlugin;
//# sourceMappingURL=index.js.map