@verdaccio/local-storage
Version:
Local storage implementation
225 lines (224 loc) • 7.09 kB
JavaScript
const require_runtime = require("./_virtual/_rolldown/runtime.js");
const require_dir_utils = require("./dir-utils.js");
const require_local_fs = require("./local-fs.js");
const require_pkg_utils = require("./pkg-utils.js");
const require_token = require("./token.js");
let debug = require("debug");
debug = require_runtime.__toESM(debug);
let fs = require("fs");
fs = require_runtime.__toESM(fs);
let lodash = require("lodash");
lodash = require_runtime.__toESM(lodash);
let mkdirp = require("mkdirp");
mkdirp = require_runtime.__toESM(mkdirp);
let path = require("path");
path = require_runtime.__toESM(path);
let _verdaccio_core = require("@verdaccio/core");
//#region src/local-database.ts
var debug$1 = (0, debug.default)("verdaccio:plugin:local-storage:database");
var LocalDatabase = class extends require_token.default {
path;
logger;
data;
config;
locked;
constructor(config, logger) {
super(config);
this.config = config;
this.path = this._dbGenPath(_verdaccio_core.fileUtils.Files.DatabaseName, config);
this.logger = logger;
this.locked = false;
this.data = this._fetchLocalPackages();
this._sync();
}
getSecret() {
return Promise.resolve(this.data.secret);
}
setSecret(secret) {
return new Promise((resolve) => {
this.data.secret = secret;
resolve(this._sync());
});
}
add(name, cb) {
if (this.data.list.indexOf(name) === -1) {
this.data.list.push(name);
debug$1("the private package %o has been added", name);
cb(this._sync());
} else {
debug$1("the private package %o was not added", name);
cb(null);
}
}
/**
* Filter and only match those values that the query define.
**/
async filterByQuery(results, query) {
return results.filter((item) => {
return item?.name?.match(query.text) !== null;
});
}
async getScore(_pkg) {
return Promise.resolve({
final: 1,
detail: {
maintenance: 0,
popularity: 1,
quality: 1
}
});
}
_getCustomPackageLocalStorages() {
const storages = /* @__PURE__ */ new Map();
const { packages } = this.config;
if (packages) Object.keys(packages || {}).map((pkg) => {
const { storage } = packages[pkg];
if (typeof storage === "string") {
const storagePath = path.default.join(this.getStoragePath(), storage);
debug$1("add custom storage for %s on %s", storage, storagePath);
storages.set(storage, storagePath);
}
});
return storages;
}
async search(query) {
const results = [];
const storagePath = this.getStoragePath();
const storages = this._getCustomPackageLocalStorages();
const packagesOnStorage = await this.filterByQuery(await require_dir_utils.searchOnStorage(storagePath, storages), query);
debug$1("packages found %o", packagesOnStorage.length);
for (const storage of packagesOnStorage) {
const isPrivate = this.data.list.includes(storage.name);
const score = await this.getScore(storage);
results.push({
package: storage,
verdaccioPrivate: isPrivate,
verdaccioPkgCached: !isPrivate,
score
});
}
return results;
}
remove(name, cb) {
this.get((err, data) => {
if (err) {
cb(_verdaccio_core.errorUtils.getInternalError("error remove private package"));
this.logger.error({ err }, "remove the private package has failed @{err}");
debug$1("error on remove package %o", name);
}
const pkgName = data.indexOf(name);
if (pkgName !== -1) {
this.data.list.splice(pkgName, 1);
debug$1("remove package %o has been removed", name);
}
cb(this._sync());
});
}
/**
* Return all database elements.
* @return {Array}
*/
get(cb) {
const list = this.data.list;
const totalItems = this.data.list.length;
cb(null, list);
debug$1("get full list of packages (%o) has been fetched", totalItems);
}
getPackageStorage(packageName) {
const packageAccess = this.config.getMatchedPackagesSpec(packageName);
const packagePath = this._getLocalStoragePath(packageAccess ? packageAccess.storage : void 0);
debug$1("storage path selected: ", packagePath);
if (lodash.default.isString(packagePath) === false) {
debug$1("the package %o has no storage defined ", packageName);
return;
}
const packageStoragePath = path.default.join(path.default.resolve(path.default.dirname(this.config.self_path || ""), packagePath), packageName);
debug$1("storage absolute path: ", packageStoragePath);
return new require_local_fs.default(packageStoragePath, this.logger);
}
clean() {
this._sync();
}
getTime(time, mtime) {
return time ? time : mtime;
}
/**
* Syncronize {create} database whether does not exist.
* @return {Error|*}
*/
_sync() {
debug$1("sync database started");
if (this.locked) {
this.logger.error("Database is locked, please check error message printed during startup to prevent data loss.");
return /* @__PURE__ */ new Error("Verdaccio database is locked, please contact your administrator to checkout logs during verdaccio startup.");
}
try {
const folderName = path.default.dirname(this.path);
mkdirp.default.sync(folderName);
debug$1("sync folder %o created succeed", folderName);
} catch (err) {
debug$1("sync create folder has failed with error: %o", err);
return null;
}
try {
fs.default.writeFileSync(this.path, JSON.stringify(this.data));
debug$1("sync write succeed");
return null;
} catch (err) {
debug$1("sync failed %o", err);
return err;
}
}
getBaseConfigPath() {
return path.default.dirname(this.config.configPath);
}
/**
* The field storage could be absolute or relative.
* If relative, it will be resolved against the config path.
* If absolute, it will be returned as is.
**/
getStoragePath() {
const { storage } = this.config;
if (typeof storage !== "string") throw new TypeError("storage field is mandatory");
const storagePath = path.default.isAbsolute(storage) ? storage : path.default.normalize(path.default.join(this.getBaseConfigPath(), storage));
debug$1("storage path %o", storagePath);
return storagePath;
}
/**
* Verify the right local storage location.
* @param {String} path
* @return {String}
* @private
*/
_getLocalStoragePath(storage) {
const globalConfigStorage = this.config ? this.config.storage : void 0;
if (lodash.default.isNil(globalConfigStorage)) throw new Error("global storage is required for this plugin");
else {
if (lodash.default.isNil(storage) === false && lodash.default.isString(storage)) return path.default.join(globalConfigStorage, storage);
return globalConfigStorage;
}
}
/**
* Fetch local packages.
* @private
* @return {Object}
*/
_fetchLocalPackages() {
const emptyDatabase = {
list: [],
secret: ""
};
try {
return require_pkg_utils.loadPrivatePackages(this.path, this.logger);
} catch (err) {
if (err.code !== "ENOENT") {
this.locked = true;
this.logger.error("Failed to read package database file, please check the error printed below:\n", `File Path: ${this.path}\n\n ${err.message}`);
}
return emptyDatabase;
}
}
};
//#endregion
exports.default = LocalDatabase;
//# sourceMappingURL=local-database.js.map