@verdaccio/local-storage
Advanced tools
Comparing version 11.0.0-6-next.12 to 11.0.0-6-next.13
/// <reference types="node" /> | ||
import fs from 'fs/promises'; | ||
declare const mkdirPromise: typeof fs.mkdir; | ||
declare const writeFilePromise: typeof fs.writeFile; | ||
declare const readdirPromise: typeof fs.readdir; | ||
declare const statPromise: typeof fs.stat; | ||
declare const unlinkPromise: typeof fs.unlink; | ||
declare const rmdirPromise: typeof fs.rmdir; | ||
declare const renamePromise: typeof fs.rename; | ||
export declare const readFilePromise: (path: any) => Promise<string>; | ||
export { renamePromise, mkdirPromise, writeFilePromise, readdirPromise, statPromise, unlinkPromise, rmdirPromise, }; | ||
/// <reference types="node" /> | ||
import fsCallback from 'fs'; | ||
declare const mkdirPromise: typeof fsCallback.promises.mkdir; | ||
declare const accessPromise: typeof fsCallback.promises.access; | ||
declare const writeFilePromise: typeof fsCallback.promises.writeFile; | ||
declare const readdirPromise: typeof fsCallback.promises.readdir; | ||
declare const statPromise: typeof fsCallback.promises.stat; | ||
declare const unlinkPromise: typeof fsCallback.promises.unlink; | ||
declare const rmdirPromise: typeof fsCallback.promises.rmdir; | ||
declare const renamePromise: typeof fsCallback.promises.rename; | ||
declare const openPromise: typeof fsCallback.promises.open; | ||
declare const readFilePromise: (path: any) => Promise<string>; | ||
declare function fstatPromise(fd: number): Promise<fsCallback.Stats>; | ||
export { readFilePromise, renamePromise, mkdirPromise, writeFilePromise, readdirPromise, statPromise, accessPromise, unlinkPromise, rmdirPromise, openPromise, fstatPromise, }; |
@@ -6,4 +6,8 @@ "use strict"; | ||
}); | ||
exports.writeFilePromise = exports.unlinkPromise = exports.statPromise = exports.rmdirPromise = exports.renamePromise = exports.readdirPromise = exports.readFilePromise = exports.mkdirPromise = void 0; | ||
exports.accessPromise = void 0; | ||
exports.fstatPromise = fstatPromise; | ||
exports.writeFilePromise = exports.unlinkPromise = exports.statPromise = exports.rmdirPromise = exports.renamePromise = exports.readdirPromise = exports.readFilePromise = exports.openPromise = exports.mkdirPromise = void 0; | ||
var _fs = _interopRequireDefault(require("fs")); | ||
var _promises = _interopRequireDefault(require("fs/promises")); | ||
@@ -16,2 +20,4 @@ | ||
exports.mkdirPromise = mkdirPromise; | ||
const accessPromise = _promises.default.access; | ||
exports.accessPromise = accessPromise; | ||
const writeFilePromise = _promises.default.writeFile; | ||
@@ -29,2 +35,4 @@ exports.writeFilePromise = writeFilePromise; | ||
exports.renamePromise = renamePromise; | ||
const openPromise = _promises.default.open; | ||
exports.openPromise = openPromise; | ||
@@ -36,2 +44,14 @@ const readFilePromise = async path => { | ||
exports.readFilePromise = readFilePromise; | ||
function fstatPromise(fd) { | ||
return new Promise((resolve, reject) => { | ||
_fs.default.fstat(fd, function (err, stats) { | ||
if (err) { | ||
return reject(err); | ||
} | ||
return resolve(stats); | ||
}); | ||
}); | ||
} | ||
//# sourceMappingURL=fs.js.map |
@@ -38,3 +38,3 @@ "use strict"; | ||
const DB_NAME = process.env.VERDACCIO_STORAGE_NAME ?? _core.fileUtils.Files.DatabaseName; | ||
const debug = (0, _debug.default)('verdaccio:plugin:local-storage:experimental'); | ||
const debug = (0, _debug.default)('verdaccio:plugin:local-storage'); | ||
const ERROR_DB_LOCKED = 'Database is locked, please check error message printed during startup to prevent data loss'; | ||
@@ -50,4 +50,8 @@ exports.ERROR_DB_LOCKED = ERROR_DB_LOCKED; | ||
this.data = undefined; | ||
debug('config path %o', config.configPath); | ||
this.path = (0, _utils2._dbGenPath)(DB_NAME, config); | ||
this.storages = this._getCustomPackageLocalStorages(); | ||
this.logger.debug({ | ||
path: this.path | ||
}, 'local storage path @{path}'); | ||
debug('plugin storage path %o', this.path); | ||
@@ -117,3 +121,3 @@ } | ||
getBaseConfigPath() { | ||
return _path.default.dirname(this.config.config_path); | ||
return _path.default.dirname(this.config.configPath); | ||
} | ||
@@ -278,3 +282,3 @@ /** | ||
await (0, _fs.writeFilePromise)(this.path, JSON.stringify(this.data)); | ||
debug('sync write succeed'); | ||
debug('sync write succeeded'); | ||
return null; | ||
@@ -293,4 +297,4 @@ } catch (err) { | ||
if (_lodash.default.isNil(globalConfigStorage)) { | ||
this.logger.error('property storage in config.yaml is required for using this plugin'); | ||
throw new Error('property storage in config.yaml is required for using this plugin'); | ||
this.logger.error('property storage in config.yaml is required for using this plugin'); | ||
throw new Error('property storage in config.yaml is required for using this plugin'); | ||
} else { | ||
@@ -297,0 +301,0 @@ if (typeof storage === 'string') { |
@@ -0,4 +1,5 @@ | ||
/// <reference types="node" /> | ||
import { Readable, Writable } from 'stream'; | ||
import { VerdaccioError } from '@verdaccio/core'; | ||
import { ReadTarball } from '@verdaccio/streams'; | ||
import { Callback, ILocalPackageManager, IUploadTarball, Logger, Package } from '@verdaccio/types'; | ||
import { ILocalPackageManager, Logger, Manifest } from '@verdaccio/types'; | ||
export declare const fileExist = "EEXISTS"; | ||
@@ -8,7 +9,7 @@ export declare const noSuchFile = "ENOENT"; | ||
export declare const packageJSONFileName = "package.json"; | ||
export declare const fSError: (message: string, code?: number) => VerdaccioError; | ||
export declare function renameTmpNext(src: string, dst: string): Promise<void>; | ||
export declare type ILocalFSPackageManager = ILocalPackageManager & { | ||
path: string; | ||
}; | ||
export declare const fSError: (message: string, code?: number) => VerdaccioError; | ||
export declare function renameTmp(src: string, dst: string): Promise<void>; | ||
export default class LocalFS implements ILocalFSPackageManager { | ||
@@ -19,18 +20,2 @@ path: string; | ||
/** | ||
* This function allows to update the package thread-safely | ||
Algorithm: | ||
1. lock package.json for writing | ||
2. read package.json | ||
3. updateFn(pkg, cb), and wait for cb | ||
4. write package.json.tmp | ||
5. move package.json.tmp package.json | ||
6. callback(err?) | ||
* @param {*} name | ||
* @param {*} updateHandler | ||
* @param {*} onWrite | ||
* @param {*} transformPackage | ||
* @param {*} onEnd | ||
*/ | ||
updatePackage(name: string, updateHandler: Callback, onWrite: Callback, transformPackage: Function, onEnd: Callback): void; | ||
/** | ||
* This function allows to update the package | ||
@@ -55,23 +40,46 @@ * This function handle the update package logic, for this plugin | ||
*/ | ||
updatePackageNext(packageName: string, handleUpdate: (manifest: Package) => Promise<Package>): Promise<Package>; | ||
updatePackage(packageName: string, handleUpdate: (manifest: Manifest) => Promise<Manifest>): Promise<Manifest>; | ||
deletePackage(packageName: string): Promise<void>; | ||
removePackage(): Promise<void>; | ||
createPackage(name: string, value: Package, cb: Callback): void; | ||
savePackage(name: string, value: Package, cb: Callback): void; | ||
savePackageNext(name: string, value: Package): Promise<void>; | ||
readPackageNext(name: string): Promise<Package>; | ||
readPackage(name: string, cb: Callback): void; | ||
writeTarball(name: string): IUploadTarball; | ||
readTarball(name: string): ReadTarball; | ||
private _createFile; | ||
/** | ||
* Verify if the package exists already. | ||
* @param name package name | ||
* @returns | ||
*/ | ||
hasPackage(): Promise<boolean>; | ||
/** | ||
* Create a package in the local storage, if package already exist fails. | ||
* @param name package name | ||
* @param manifest package manifest | ||
*/ | ||
createPackage(name: string, manifest: Manifest): Promise<void>; | ||
savePackage(name: string, value: Manifest): Promise<void>; | ||
readPackage(name: string): Promise<Manifest>; | ||
hasTarball(fileName: string): Promise<boolean>; | ||
private removeTempFile; | ||
/** | ||
* Write a tarball into the storage | ||
* @param fileName package name | ||
* @param param1 | ||
* @returns | ||
*/ | ||
writeTarball(fileName: string, { signal }: { | ||
signal: any; | ||
}): Promise<Writable>; | ||
/** | ||
* Read a tarball from the storage | ||
* @param tarballName tarball name eg: foo-1.0.0.tgz | ||
* @param options {signal} abort signal | ||
* @returns Readable stream | ||
*/ | ||
readTarball(tarballName: string, { signal }: { | ||
signal: any; | ||
}): Promise<Readable>; | ||
private _readStorageFile; | ||
private _convertToString; | ||
private _getStorage; | ||
private _writeFile; | ||
_getStorage(fileName?: string): string; | ||
private writeTempFileAndRename; | ||
private writeFileNext; | ||
private writeFile; | ||
private _lockAndReadJSON; | ||
private _unlockJSON; | ||
private _lockAndReadJSONNext; | ||
private _unlockJSONNext; | ||
} |
@@ -7,3 +7,3 @@ "use strict"; | ||
exports.packageJSONFileName = exports.noSuchFile = exports.fileExist = exports.fSError = exports.default = void 0; | ||
exports.renameTmpNext = renameTmpNext; | ||
exports.renameTmp = renameTmp; | ||
exports.resourceNotAvailable = void 0; | ||
@@ -15,6 +15,8 @@ | ||
var _lodash = _interopRequireDefault(require("lodash")); | ||
var _path = _interopRequireDefault(require("path")); | ||
var _sanitizeFilename = _interopRequireDefault(require("sanitize-filename")); | ||
var _stream = require("stream"); | ||
var _core = require("@verdaccio/core"); | ||
@@ -24,4 +26,2 @@ | ||
var _streams = require("@verdaccio/streams"); | ||
var _fs2 = require("./fs"); | ||
@@ -57,40 +57,10 @@ | ||
const renameTmp = function (src, dst, _cb) { | ||
const cb = err => { | ||
if (err) { | ||
_fs.default.unlink(src, () => {}); | ||
} | ||
async function renameTmp(src, dst) { | ||
debug('rename %s to %s', src, dst); | ||
_cb(err); | ||
}; | ||
if (process.platform !== 'win32') { | ||
return _fs.default.rename(src, dst, cb); | ||
} // windows can't remove opened file, | ||
// but it seem to be able to rename it | ||
const tmp = tempFile(dst); | ||
_fs.default.rename(dst, tmp, function (err) { | ||
_fs.default.rename(src, dst, cb); | ||
if (!err) { | ||
_fs.default.unlink(tmp, () => {}); | ||
} | ||
}); | ||
}; | ||
async function renameTmpNext(src, dst) { | ||
if (process.platform !== 'win32') { | ||
try { | ||
await (0, _fs2.renamePromise)(src, dst); | ||
} catch (err) { | ||
debug('error rename %s error %s', src, err === null || err === void 0 ? void 0 : err.message); | ||
await (0, _fs2.unlinkPromise)(src); | ||
} else { | ||
// TODO: review if this still the cases | ||
// windows can't remove opened file, | ||
// but it seem to be able to rename it | ||
const tmp = tempFile(dst); | ||
await (0, _fs2.renamePromise)(dst, tmp); | ||
await (0, _fs2.renamePromise)(src, dst); | ||
await (0, _fs2.unlinkPromise)(tmp); | ||
} | ||
@@ -105,70 +75,2 @@ } | ||
/** | ||
* This function allows to update the package thread-safely | ||
Algorithm: | ||
1. lock package.json for writing | ||
2. read package.json | ||
3. updateFn(pkg, cb), and wait for cb | ||
4. write package.json.tmp | ||
5. move package.json.tmp package.json | ||
6. callback(err?) | ||
* @param {*} name | ||
* @param {*} updateHandler | ||
* @param {*} onWrite | ||
* @param {*} transformPackage | ||
* @param {*} onEnd | ||
*/ | ||
updatePackage(name, updateHandler, onWrite, transformPackage, onEnd) { | ||
this._lockAndReadJSON(packageJSONFileName, (err, json) => { | ||
let locked = false; | ||
const self = this; // callback that cleans up lock first | ||
const unLockCallback = function (lockError) { | ||
// eslint-disable-next-line prefer-rest-params | ||
const _args = arguments; | ||
if (locked) { | ||
debug('unlock %s', packageJSONFileName); | ||
self._unlockJSON(packageJSONFileName, () => { | ||
// ignore any error from the unlock | ||
if (lockError !== null) { | ||
debug('lock file: %o has failed with error %o', name, lockError); | ||
} | ||
onEnd.apply(lockError, _args); | ||
}); | ||
} else { | ||
debug('file: %o has been updated', name); | ||
onEnd(..._args); | ||
} | ||
}; // ////////////////////////////////////// | ||
if (!err) { | ||
locked = true; | ||
debug('file: %o has been locked', name); | ||
} | ||
if (_lodash.default.isNil(err) === false) { | ||
if (err.code === resourceNotAvailable) { | ||
return unLockCallback(_core.errorUtils.getInternalError('resource temporarily unavailable')); | ||
} else if (err.code === noSuchFile) { | ||
return unLockCallback(_core.errorUtils.getNotFound()); | ||
} else { | ||
return unLockCallback(err); | ||
} | ||
} | ||
updateHandler(json, err => { | ||
if (err) { | ||
return unLockCallback(err); | ||
} | ||
onWrite(name, transformPackage(json), unLockCallback); | ||
}); | ||
}); | ||
} | ||
/** | ||
* This function allows to update the package | ||
@@ -195,3 +97,3 @@ * This function handle the update package logic, for this plugin | ||
async updatePackageNext(packageName, handleUpdate) { | ||
async updatePackage(packageName, handleUpdate) { | ||
// this plugin lock files on write, we handle all possible scenarios | ||
@@ -202,3 +104,3 @@ let locked = false; | ||
try { | ||
const manifest = await this._lockAndReadJSONNext(packageJSONFileName); | ||
const manifest = await this._lockAndReadJSON(packageJSONFileName); | ||
locked = true; | ||
@@ -209,3 +111,3 @@ manifestUpdated = await handleUpdate(manifest); | ||
debug('unlock %s', packageJSONFileName); | ||
await this._unlockJSONNext(packageJSONFileName); | ||
await this._unlockJSON(packageJSONFileName); | ||
this.logger.debug({ | ||
@@ -231,3 +133,3 @@ packageName | ||
try { | ||
await this._unlockJSONNext(packageJSONFileName); // after unlock bubble up error. | ||
await this._unlockJSON(packageJSONFileName); // after unlock bubble up error. | ||
@@ -260,21 +162,59 @@ throw err; | ||
} | ||
/** | ||
* Verify if the package exists already. | ||
* @param name package name | ||
* @returns | ||
*/ | ||
createPackage(name, value, cb) { | ||
debug('create a package %o', name); | ||
this._createFile(this._getStorage(packageJSONFileName), this._convertToString(value), cb); | ||
async hasPackage() { | ||
const pathName = this._getStorage(packageJSONFileName); | ||
try { | ||
const stat = await (0, _fs2.statPromise)(pathName); | ||
return stat.isFile(); | ||
} catch (err) { | ||
if (err.code === noSuchFile) { | ||
debug('dir: %o does not exist %s', pathName, err === null || err === void 0 ? void 0 : err.code); | ||
return false; | ||
} else { | ||
this.logger.error('error on verify a package exist %o', err); | ||
throw _core.errorUtils.getInternalError('error on verify a package exist'); | ||
} | ||
} | ||
} | ||
/** | ||
* Create a package in the local storage, if package already exist fails. | ||
* @param name package name | ||
* @param manifest package manifest | ||
*/ | ||
savePackage(name, value, cb) { | ||
debug('save a package %o', name); | ||
this._writeFile(this._getStorage(packageJSONFileName), this._convertToString(value), cb); | ||
async createPackage(name, manifest) { | ||
debug('create a a new package %o', name); | ||
const pathPackage = this._getStorage(packageJSONFileName); | ||
try { | ||
// https://nodejs.org/dist/latest-v17.x/docs/api/fs.html#file-system-flags | ||
// 'wx': Like 'w' but fails if the path exists | ||
await (0, _fs2.openPromise)(pathPackage, 'wx'); | ||
} catch (err) { | ||
// cannot override a pacakge that already exist | ||
if (err.code === 'EEXIST') { | ||
debug('file %o cannot be created, it already exists: %o', name); | ||
throw fSError(fileExist); | ||
} | ||
} // Create a new file and itĀ“s folder if does not exist previously | ||
await this.writeFile(pathPackage, this._convertToString(manifest)); | ||
} | ||
async savePackageNext(name, value) { | ||
async savePackage(name, value) { | ||
debug('save a package %o', name); | ||
await this.writeFileNext(this._getStorage(packageJSONFileName), this._convertToString(value)); | ||
await this.writeFile(this._getStorage(packageJSONFileName), this._convertToString(value)); | ||
} | ||
async readPackageNext(name) { | ||
async readPackage(name) { | ||
debug('read a package %o', name); | ||
@@ -285,23 +225,6 @@ | ||
const data = JSON.parse(res.toString('utf8')); | ||
debug('read storage file %o has succeed', name); | ||
debug('read storage file %o has succeeded', name); | ||
return data; | ||
} catch (err) { | ||
debug('parse error'); | ||
this.logger.error({ | ||
err, | ||
name | ||
}, 'error @{err.message} on parse @{name}'); | ||
throw err; | ||
} | ||
} | ||
readPackage(name, cb) { | ||
debug('read a package %o', name); | ||
this._readStorageFile(this._getStorage(packageJSONFileName)).then(res => { | ||
try { | ||
const data = JSON.parse(res.toString('utf8')); | ||
debug('read storage file %o has succeed', name); | ||
cb(null, data); | ||
} catch (err) { | ||
if (err.code !== noSuchFile) { | ||
debug('parse error'); | ||
@@ -312,136 +235,126 @@ this.logger.error({ | ||
}, 'error @{err.message} on parse @{name}'); | ||
throw err; | ||
} | ||
}).catch(err => { | ||
debug('error on read storage file %o', err.message); | ||
return cb(err); | ||
}); | ||
throw err; | ||
} | ||
} | ||
writeTarball(name) { | ||
const uploadStream = new _streams.UploadTarball({}); | ||
debug('write a tarball for a package %o', name); | ||
let _ended = 0; | ||
uploadStream.on('end', function () { | ||
_ended = 1; | ||
async hasTarball(fileName) { | ||
const pathName = this._getStorage(fileName); | ||
return new Promise(resolve => { | ||
(0, _fs2.accessPromise)(pathName).then(() => { | ||
resolve(true); | ||
}).catch(() => resolve(false)); | ||
}); | ||
} // remove the temporary file | ||
const pathName = this._getStorage(name); | ||
_fs.default.access(pathName, fileNotFound => { | ||
const exists = !fileNotFound; | ||
async removeTempFile(temporalName) { | ||
debug('remove temporal file %o', temporalName); | ||
await (0, _fs2.unlinkPromise)(temporalName); | ||
debug('removed temporal file %o', temporalName); | ||
} | ||
/** | ||
* Write a tarball into the storage | ||
* @param fileName package name | ||
* @param param1 | ||
* @returns | ||
*/ | ||
if (exists) { | ||
uploadStream.emit('error', fSError(fileExist)); | ||
} else { | ||
const temporalName = _path.default.join(this.path, `${name}.tmp-${String(Math.random()).replace(/^0\./, '')}`); | ||
debug('write a temporal name %o', temporalName); | ||
async writeTarball(fileName, { | ||
signal | ||
}) { | ||
debug('write a tarball %o', fileName); | ||
const file = _fs.default.createWriteStream(temporalName); | ||
const pathName = this._getStorage(fileName); // create a temporary file to avoid conflicts or prev corruption files | ||
const removeTempFile = () => _fs.default.unlink(temporalName, () => {}); | ||
let opened = false; | ||
uploadStream.pipe(file); | ||
const temporalName = _path.default.join(this.path, `${fileName}.tmp-${String(Math.random()).replace(/^0\./, '')}`); | ||
uploadStream.done = function () { | ||
const onend = function () { | ||
file.on('close', function () { | ||
renameTmp(temporalName, pathName, function (err) { | ||
if (err) { | ||
uploadStream.emit('error', err); | ||
} else { | ||
uploadStream.emit('success'); | ||
} | ||
}); | ||
}); | ||
file.end(); | ||
}; | ||
debug('write a temporal name %o', temporalName); | ||
let opened = false; | ||
if (_ended) { | ||
onend(); | ||
} else { | ||
uploadStream.on('end', onend); | ||
} | ||
}; | ||
const writeStream = _fs.default.createWriteStream(temporalName); | ||
uploadStream.abort = function () { | ||
if (opened) { | ||
opened = false; | ||
file.on('close', function () { | ||
removeTempFile(); | ||
}); | ||
} else { | ||
// if the file does not recieve any byte never is opened and has to be removed anyway. | ||
removeTempFile(); | ||
} | ||
writeStream.on('open', () => { | ||
opened = true; | ||
}); | ||
writeStream.on('error', async err => { | ||
if (opened) { | ||
this.logger.error({ | ||
err: err.message, | ||
fileName | ||
}, 'error on open write tarball for @{pkgName}'); // TODO: maybe add .once | ||
file.end(); | ||
}; | ||
writeStream.on('close', async () => { | ||
await this.removeTempFile(temporalName); | ||
}); | ||
} else { | ||
this.logger.error({ | ||
err: err.message, | ||
fileName | ||
}, 'error a non open write tarball for @{pkgName}'); | ||
await this.removeTempFile(temporalName); | ||
} | ||
}); // the 'close' event is emitted when the stream and any of its | ||
// underlying resources (a file descriptor, for example) have been closed. | ||
// TODO: maybe add .once | ||
file.on('open', function () { | ||
opened = true; // re-emitting open because it's handled in storage.js | ||
writeStream.on('close', async () => { | ||
try { | ||
await renameTmp(temporalName, pathName); | ||
} catch (err) { | ||
this.logger.error({ | ||
err | ||
}, 'error on rename temporal file, please report this is a bug @{err}'); | ||
} | ||
}); // if upload is aborted, we clean up the temporal file | ||
uploadStream.emit('open'); | ||
signal.addEventListener('abort', async () => { | ||
if (opened) { | ||
// close always happens, even if error | ||
writeStream.once('close', async () => { | ||
await this.removeTempFile(temporalName); | ||
}); | ||
file.on('error', function (err) { | ||
uploadStream.emit('error', err); | ||
}); | ||
} else { | ||
await this.removeTempFile(temporalName); | ||
} | ||
}, { | ||
once: true | ||
}); | ||
return uploadStream; | ||
return writeStream; | ||
} | ||
/** | ||
* Read a tarball from the storage | ||
* @param tarballName tarball name eg: foo-1.0.0.tgz | ||
* @param options {signal} abort signal | ||
* @returns Readable stream | ||
*/ | ||
readTarball(name) { | ||
const pathName = this._getStorage(name); | ||
debug('read a a tarball %o on path %o', name, pathName); | ||
const readTarballStream = new _streams.ReadTarball({}); | ||
async readTarball(tarballName, { | ||
signal | ||
}) { | ||
const pathName = this._getStorage(tarballName); | ||
const readStream = _fs.default.createReadStream(pathName); | ||
debug('read a tarball %o', pathName); | ||
const readStream = (0, _stream.addAbortSignal)(signal, _fs.default.createReadStream(pathName)); | ||
readStream.on('open', async function (fileDescriptorId) { | ||
// if abort, the descriptor is null | ||
debug('file descriptor id %o', fileDescriptorId); | ||
readStream.on('error', function (err) { | ||
debug('error on read a tarball %o with error %o', name, err); | ||
readTarballStream.emit('error', err); | ||
if (fileDescriptorId) { | ||
const stats = await (0, _fs2.fstatPromise)(fileDescriptorId); | ||
debug('file size %o', stats.size); | ||
readStream.emit('content-length', stats.size); | ||
} | ||
}); | ||
readStream.on('open', function (fd) { | ||
_fs.default.fstat(fd, function (err, stats) { | ||
if (_lodash.default.isNil(err) === false) { | ||
debug('error on read a tarball %o with error %o', name, err); | ||
return readTarballStream.emit('error', err); | ||
} | ||
readTarballStream.emit('content-length', stats.size); | ||
readTarballStream.emit('open'); | ||
debug('open on read a tarball %o', name); | ||
readStream.pipe(readTarballStream); | ||
}); | ||
readStream.on('error', error => { | ||
debug('not tarball found %o for %s message %s', pathName, tarballName, error.message); | ||
}); | ||
readTarballStream.abort = function () { | ||
debug('abort on read a tarball %o', name); | ||
readStream.close(); | ||
}; | ||
return readTarballStream; | ||
return readStream; | ||
} | ||
_createFile(name, contents, callback) { | ||
debug(' create a new file: %o', name); | ||
_fs.default.open(name, 'wx', err => { | ||
if (err) { | ||
// native EEXIST used here to check exception on fs.open | ||
if (err.code === 'EEXIST') { | ||
debug('file %o cannot be created, it already exists: %o', name); | ||
return callback(fSError(fileExist)); | ||
} | ||
} | ||
this._writeFile(name, contents, callback); | ||
}); | ||
} | ||
async _readStorageFile(name) { | ||
@@ -460,43 +373,12 @@ debug('reading the file: %o', name); | ||
_convertToString(value) { | ||
return JSON.stringify(value, null, '\t'); | ||
return JSON.stringify(value); | ||
} | ||
_getStorage(fileName = '') { | ||
const storagePath = _path.default.join(this.path, fileName); | ||
const storagePath = _path.default.join(this.path, (0, _sanitizeFilename.default)(fileName)); | ||
debug('get storage %s', storagePath); | ||
return storagePath; | ||
} | ||
_writeFile(dest, data, cb) { | ||
const createTempFile = cb => { | ||
const tempFilePath = tempFile(dest); | ||
_fs.default.writeFile(tempFilePath, data, err => { | ||
if (err) { | ||
debug('error on write the file: %o', dest); | ||
return cb(err); | ||
} | ||
debug('creating a new file:: %o', dest); | ||
renameTmp(tempFilePath, dest, cb); | ||
}); | ||
}; | ||
createTempFile(err => { | ||
if (err && err.code === noSuchFile) { | ||
_fs.default.mkdir(_path.default.dirname(dest), { | ||
recursive: true | ||
}, function (err) { | ||
if (err) { | ||
return cb(err); | ||
} | ||
createTempFile(cb); | ||
}); | ||
} else { | ||
cb(err); | ||
} | ||
}); | ||
} | ||
async writeTempFileAndRename(dest, fileContent) { | ||
@@ -506,7 +388,8 @@ const tempFilePath = tempFile(dest); | ||
try { | ||
// write file on temp location | ||
// write file on temp locatio | ||
// TODO: we need to handle when directory does not exist | ||
await (0, _fs2.writeFilePromise)(tempFilePath, fileContent); | ||
debug('creating a new file:: %o', dest); // rename tmp file to original | ||
await renameTmpNext(tempFilePath, dest); | ||
await renameTmp(tempFilePath, dest); | ||
} catch (err) { | ||
@@ -518,14 +401,23 @@ debug('error on write the file: %o', dest); | ||
async writeFileNext(destiny, fileContent) { | ||
async writeFile(destiny, fileContent) { | ||
try { | ||
await this.writeTempFileAndRename(destiny, fileContent); | ||
debug('write file success %s', destiny); | ||
} catch (err) { | ||
if (err && err.code === noSuchFile) { | ||
// if fails, we create the folder for the package | ||
await (0, _fs2.mkdirPromise)(_path.default.dirname(destiny), { | ||
const dir = _path.default.dirname(destiny); // if fails, we create the folder for the package | ||
debug('write file has failed, creating folder %s', dir); | ||
await (0, _fs2.mkdirPromise)(dir, { | ||
recursive: true | ||
}); // we try again create the temp file | ||
debug('writing a temp file %s', destiny); | ||
await this.writeTempFileAndRename(destiny, fileContent); | ||
debug('write file success %s', destiny); | ||
} else { | ||
this.logger.error({ | ||
err: err.message | ||
}, 'error on write file @{err}'); | ||
throw err; | ||
@@ -536,32 +428,7 @@ } | ||
_lockAndReadJSON(name, cb) { | ||
async _lockAndReadJSON(name) { | ||
const fileName = this._getStorage(name); | ||
debug('lock and read a file %o', fileName); | ||
(0, _fileLocking.readFile)(fileName, { | ||
lock: true, | ||
parse: true | ||
}, (err, res) => { | ||
if (err) { | ||
this.logger.error({ | ||
err | ||
}, 'error on lock file @{err.message}'); | ||
debug('error on lock and read json for file: %o', name); | ||
return cb(err); | ||
} | ||
debug('lock and read json for file: %o', name); | ||
return cb(null, res); | ||
}); | ||
} | ||
_unlockJSON(name, cb) { | ||
(0, _fileLocking.unlockFile)(this._getStorage(name), cb); | ||
} | ||
async _lockAndReadJSONNext(name) { | ||
const fileName = this._getStorage(name); | ||
debug('lock and read a file %o', fileName); | ||
try { | ||
@@ -582,3 +449,3 @@ const data = await (0, _fileLocking.readFileNext)(fileName, { | ||
async _unlockJSONNext(name) { | ||
async _unlockJSON(name) { | ||
await (0, _fileLocking.unlockFileNext)(this._getStorage(name)); | ||
@@ -585,0 +452,0 @@ } |
@@ -10,2 +10,2 @@ /// <reference types="node" /> | ||
}[]>; | ||
export declare function _dbGenPath(dbName: string, config: Pick<Config, 'config_path' | 'storage'>): string; | ||
export declare function _dbGenPath(dbName: string, config: Pick<Config, 'configPath' | 'storage'>): string; |
@@ -98,4 +98,4 @@ "use strict"; | ||
function _dbGenPath(dbName, config) { | ||
return _path.default.join(_path.default.resolve(_path.default.dirname(config.config_path || ''), config.storage, dbName)); | ||
return _path.default.join(_path.default.resolve(_path.default.dirname(config.configPath || ''), config.storage, dbName)); | ||
} | ||
//# sourceMappingURL=utils.js.map |
146
package.json
{ | ||
"name": "@verdaccio/local-storage", | ||
"version": "11.0.0-6-next.12", | ||
"description": "Local storage implementation", | ||
"keywords": [ | ||
"private", | ||
"package", | ||
"repository", | ||
"registry", | ||
"enterprise", | ||
"modules", | ||
"proxy", | ||
"server", | ||
"verdaccio" | ||
], | ||
"author": "Juan Picado <juanpicado19@gmail.com>", | ||
"license": "MIT", | ||
"homepage": "https://verdaccio.org", | ||
"repository": { | ||
"type": "https", | ||
"url": "https://github.com/verdaccio/verdaccio", | ||
"directory": "packages/core/local-storage" | ||
}, | ||
"bugs": { | ||
"url": "https://github.com/verdaccio/verdaccio/issues" | ||
}, | ||
"publishConfig": { | ||
"access": "public" | ||
}, | ||
"main": "./build/index.js", | ||
"types": "./build/index.d.ts", | ||
"files": [ | ||
"build/" | ||
], | ||
"engines": { | ||
"node": ">=14", | ||
"npm": ">=7" | ||
}, | ||
"dependencies": { | ||
"@verdaccio/core": "6.0.0-6-next.5", | ||
"@verdaccio/file-locking": "11.0.0-6-next.4", | ||
"@verdaccio/streams": "11.0.0-6-next.5", | ||
"async": "3.2.3", | ||
"core-js": "3.20.3", | ||
"debug": "4.3.3", | ||
"globby": "11.1.0", | ||
"lockfile": "1.0.4", | ||
"sanitize-filename": "1.6.3", | ||
"lodash": "4.17.21", | ||
"lowdb": "1.0.0", | ||
"lru-cache": "6.0.0" | ||
}, | ||
"devDependencies": { | ||
"@types/minimatch": "3.0.5", | ||
"@verdaccio/types": "11.0.0-6-next.11", | ||
"@verdaccio/config": "6.0.0-6-next.13", | ||
"@verdaccio/utils": "6.0.0-6-next.11", | ||
"minimatch": "3.0.4", | ||
"tmp-promise": "3.0.3" | ||
}, | ||
"funding": { | ||
"type": "opencollective", | ||
"url": "https://opencollective.com/verdaccio" | ||
}, | ||
"scripts": { | ||
"clean": "rimraf ./build", | ||
"test": "cross-env NODE_ENV=test BABEL_ENV=test jest", | ||
"type-check": "tsc --noEmit -p tsconfig.build.json", | ||
"build:types": "tsc --emitDeclarationOnly -p tsconfig.build.json", | ||
"build:js": "babel src/ --out-dir build/ --copy-files --extensions \".ts,.tsx\" --source-maps", | ||
"watch": "pnpm build:js -- --watch", | ||
"build": "pnpm run build:js && pnpm run build:types" | ||
} | ||
} | ||
"name": "@verdaccio/local-storage", | ||
"version": "11.0.0-6-next.13", | ||
"description": "Local storage implementation", | ||
"keywords": [ | ||
"private", | ||
"package", | ||
"repository", | ||
"registry", | ||
"enterprise", | ||
"modules", | ||
"proxy", | ||
"server", | ||
"verdaccio" | ||
], | ||
"author": "Juan Picado <juanpicado19@gmail.com>", | ||
"license": "MIT", | ||
"homepage": "https://verdaccio.org", | ||
"repository": { | ||
"type": "https", | ||
"url": "https://github.com/verdaccio/verdaccio", | ||
"directory": "packages/core/local-storage" | ||
}, | ||
"bugs": { | ||
"url": "https://github.com/verdaccio/verdaccio/issues" | ||
}, | ||
"publishConfig": { | ||
"access": "public" | ||
}, | ||
"main": "./build/index.js", | ||
"types": "./build/index.d.ts", | ||
"files": [ | ||
"build/" | ||
], | ||
"engines": { | ||
"node": ">=14", | ||
"npm": ">=7" | ||
}, | ||
"dependencies": { | ||
"@verdaccio/core": "6.0.0-6-next.6", | ||
"@verdaccio/file-locking": "11.0.0-6-next.5", | ||
"core-js": "3.24.1", | ||
"debug": "4.3.4", | ||
"globby": "11.1.0", | ||
"lockfile": "1.0.4", | ||
"sanitize-filename": "1.6.3", | ||
"lodash": "4.17.21", | ||
"lowdb": "1.0.0", | ||
"lru-cache": "6.0.0" | ||
}, | ||
"devDependencies": { | ||
"@types/minimatch": "3.0.5", | ||
"@verdaccio/types": "11.0.0-6-next.13", | ||
"@verdaccio/config": "6.0.0-6-next.15", | ||
"@verdaccio/logger": "6.0.0-6-next.12", | ||
"@verdaccio/utils": "6.0.0-6-next.12", | ||
"@verdaccio/test-helper": "1.1.0-6-next.1", | ||
"minimatch": "3.1.2" | ||
}, | ||
"funding": { | ||
"type": "opencollective", | ||
"url": "https://opencollective.com/verdaccio" | ||
}, | ||
"scripts": { | ||
"clean": "rimraf ./build", | ||
"test": "jest", | ||
"type-check": "tsc --noEmit -p tsconfig.build.json", | ||
"build:types": "tsc --emitDeclarationOnly -p tsconfig.build.json", | ||
"build:js": "babel src/ --out-dir build/ --copy-files --extensions \".ts,.tsx\" --source-maps", | ||
"watch": "pnpm build:js -- --watch", | ||
"build": "pnpm run build:js && pnpm run build:types" | ||
}, | ||
"readme": "# @verdaccio/local-storage\n\nš¦ File system storage plugin for verdaccio\n\n[![verdaccio (latest)](https://img.shields.io/npm/v/@verdaccio/local-storage/latest.svg)](https://www.npmjs.com/package/@verdaccio/local-storage)\n[![CircleCI](https://circleci.com/gh/verdaccio/local-storage/tree/master.svg?style=svg)](https://circleci.com/gh/verdaccio/local-storage/tree/master)\n[![Known Vulnerabilities](https://snyk.io/test/github/verdaccio/local-storage/badge.svg?targetFile=package.json)](https://snyk.io/test/github/verdaccio/local-storage?targetFile=package.json)\n[![codecov](https://codecov.io/gh/verdaccio/local-storage/branch/master/graph/badge.svg)](https://codecov.io/gh/verdaccio/local-storage)\n[![backers](https://opencollective.com/verdaccio/tiers/backer/badge.svg?label=Backer&color=brightgreen)](https://opencollective.com/verdaccio)\n[![discord](https://img.shields.io/discord/388674437219745793.svg)](http://chat.verdaccio.org/)\n![MIT](https://img.shields.io/github/license/mashape/apistatus.svg)\n[![node](https://img.shields.io/node/v/@verdaccio/local-storage/latest.svg)](https://www.npmjs.com/package/@verdaccio/local-storage)\n\n> This package is already built-in in verdaccio\n\n```\nnpm install @verdaccio/local-storage\n```\n\n### API\n\n### LocalDatabase\n\nThe main object that handle a JSON database the private packages.\n\n#### Constructor\n\n```\nnew LocalDatabase(config, logger);\n```\n\n- **config**: A verdaccio configuration instance.\n- **logger**: A logger instance\n\n### LocalFS\n\nA class that handle an package instance in the File System\n\n```\nnew LocalFS(packageStoragePath, logger);\n```\n\n## License\n\nVerdaccio is [MIT licensed](https://github.com/verdaccio/local-storage/blob/master/LICENSE).\n\n[![FOSSA Status](https://app.fossa.io/api/projects/git%2Bgithub.com%2Fverdaccio%2Flocal-storage.svg?type=large)](https://app.fossa.io/projects/git%2Bgithub.com%2Fverdaccio%2Flocal-storage?ref=badge_large)\n" | ||
} |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
10
115744
7
27
1178
6
+ Added@verdaccio/core@6.0.0-6-next.6(transitive)
+ Added@verdaccio/file-locking@11.0.0-6-next.5(transitive)
+ Addedajv@8.11.0(transitive)
+ Addedcore-js@3.24.1(transitive)
+ Addeddebug@4.3.4(transitive)
+ Addedfast-deep-equal@3.1.3(transitive)
+ Addedjson-schema-traverse@1.0.0(transitive)
+ Addedpunycode@2.3.1(transitive)
+ Addedrequire-from-string@2.0.2(transitive)
+ Addedsemver@7.3.7(transitive)
+ Addeduri-js@4.4.1(transitive)
- Removed@verdaccio/streams@11.0.0-6-next.5
- Removedasync@3.2.3
- Removed@verdaccio/core@6.0.0-6-next.5(transitive)
- Removed@verdaccio/file-locking@11.0.0-6-next.4(transitive)
- Removed@verdaccio/streams@11.0.0-6-next.5(transitive)
- Removedasync@3.2.3(transitive)
- Removedcore-js@3.20.3(transitive)
- Removeddebug@4.3.3(transitive)
- Removedsemver@7.3.5(transitive)
Updatedcore-js@3.24.1
Updateddebug@4.3.4