Socket
Socket
Sign inDemoInstall

s3fs

Package Overview
Dependencies
Maintainers
2
Versions
18
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

s3fs - npm Package Compare versions

Comparing version 1.1.0 to 2.0.0

775

lib/s3fs.js

@@ -25,3 +25,3 @@ /*

/* jshint maxparams: 9 */
(function (module, fsInterface, util, q, AWS, s3Utils, extend, S3WriteStream, Stats) {
(function (module, fsInterface, util, Promise, AWS, s3Utils, extend, S3WriteStream, Stats) {
/* jshint maxparams: 5 */

@@ -32,17 +32,7 @@ 'use strict';

function S3fs(options, bucket) {
function S3fs(bucket, options) {
if (!(this instanceof S3fs)) {
return new S3fs(options, bucket);
return new S3fs(bucket, options);
}
if (!options) {
throw new Error('options is required');
} else if (!(options instanceof AWS.S3)) {
if (!options.accessKeyId) {
throw new Error('accessKeyId is required');
} else if (!options.secretAccessKey) {
throw new Error('secretAccessKey is required');
}
}
if (!bucket) {

@@ -52,2 +42,6 @@ throw new Error('bucket is required');

if (typeof bucket !== 'string') {
throw new Error('bucket must be a string');
}
var bucketParts = s3Utils.decomposePath(bucket);

@@ -83,106 +77,173 @@ this.s3 = options instanceof AWS.S3 ? options : new AWS.S3(options);

S3fs.prototype.exists = function (name, cb) {
var deferred = !cb ? q.defer() : undefined,
key = this.path + s3Utils.toKey(name);
S3fs.prototype.exists = function (name, callback) {
var self = this;
var promise = new Promise(function (resolve) {
var key = self.path + s3Utils.toKey(name);
if (directoryRegExp.test(key)) {
return deferred ? deferred.resolve(true) : cb(true);
} else {
this.s3.headObject(
{
Bucket: this.bucket,
Key: key
},
function (err, data) {
if (err) {
return deferred ? deferred.reject(err) : cb(false);
}
return deferred ? deferred.resolve(data) : cb(true);
});
if (directoryRegExp.test(key)) {
return resolve(true); //TODO: Can we query S3 for this to see if the directory actually exists?
} else {
self.s3.headObject(
{
Bucket: self.bucket,
Key: key
},
function (err) {
if (err) {
return resolve(false);
}
resolve(true);
});
}
});
if (!callback) {
return promise;
}
return deferred ? deferred.promise : undefined;
promise.then(function (exists) {
callback(exists);
}, function () {
// Swallow the error (if one is hit), since exists doesn't send callback with an error in the normal FS interface.
callback(false);
});
};
S3fs.prototype.mkdir = function (path, cb) {
/**
* [fs.mkdir(path[, mode], callback)](https://nodejs.org/api/fs.html#fs_fs_mkdir_path_mode_callback)
*
* Asynchronous mkdir(2). No arguments other than a possible exception are given to the completion callback.
*
* @param path Relative path to be created
* @param callback Callback
* @returns {Promise}
*/
S3fs.prototype.mkdir = function mkdir(path, callback) {
//TODO: Add support for Mode, which by some form of magic would translate to S3 permissions. Not sure how we would maintain the same FS interface and convert it to S3 for permissions.
var promise = putObject(this.s3, this.bucket, this.path + s3Utils.toKey(path) + '/');
if (!cb) {
if (!callback) {
return promise;
}
promise.then(function (response) {
cb(undefined, response);
promise.then(function (data) {
callback(null, data);
}, function (reason) {
cb(reason);
callback(reason);
});
};
S3fs.prototype.stat = function (path, cb) {
return getFileStats(this, path, cb);
/**
* [fs.mkdirp(path[, mode], callback)](https://github.com/RiptideCloud/s3fs#s3fsmkdirppath-cb)
*
* Asynchronous recursive mkdir(2). No arguments other than a possible exception are given to the completion callback.
*
* @param path Relative path to be created
* @param callback Callback
* @returns {Promise}
*/
S3fs.prototype.mkdirp = S3fs.prototype.mkdir;
S3fs.prototype.stat = function (path, callback) {
return getFileStats(this, path, callback);
};
S3fs.prototype.lstat = function (path, cb) {
return getFileStats(this, path, cb);
S3fs.prototype.lstat = function (path, callback) {
return getFileStats(this, path, callback);
};
S3fs.prototype.readdir = function (name, cb) {
S3fs.prototype.readdir = function (name, callback) {
var prefix = this.path + s3Utils.toKey(name);
// Make sure directories have a trailing slash.
if (prefix[prefix.length - 1] !== '/') {
prefix += '/';
}
var promise = listAllObjectsFiles(this.s3, this.bucket, prefix, '/');
if (!cb) {
if (!callback) {
return promise;
}
promise.then(function (files) {
cb(null, files);
callback(null, files);
}, function (reason) {
cb(reason);
callback(reason);
});
};
S3fs.prototype.readFile = function (name, cb) {
var deferred = !cb ? q.defer() : undefined;
this.s3.getObject({
Bucket: this.bucket,
Key: this.path + s3Utils.toKey(name, this.bucket, this.path)
}, function (err, data) {
if (err) {
return deferred ? deferred.reject(err) : cb(err);
}
return deferred ? deferred.resolve(data) : cb(err, data.Body);
S3fs.prototype.readFile = function (name, options, callback) {
if (typeof options === 'function') {
callback = options;
options = undefined;
}
options = options || {};
if (options.encoding) {
options.ResponseContentEncoding = options.encoding;
delete options.encoding;
}
var promise = getObject(this.s3, this.bucket, this.path + s3Utils.toKey(name, this.bucket, this.path), options);
if (!callback) {
return promise;
}
promise.then(function (data) {
callback(null, data.Body); // Keep this in line with the FS interface and only return the contents.
}, function (reason) {
callback(reason);
});
return deferred ? deferred.promise : undefined;
};
S3fs.prototype.rmdir = function (path, cb) {
S3fs.prototype.rmdir = function (path, callback) {
var promise = deleteObject(this.s3, this.bucket, this.path + s3Utils.toKey(path) + '/');
if (!cb) {
if (!callback) {
return promise;
}
promise.then(function (response) {
cb(undefined, response);
promise.then(function (data) {
callback(null, data);
}, function (reason) {
cb(reason);
callback(reason);
});
};
S3fs.prototype.unlink = function (name, cb) {
S3fs.prototype.unlink = function (name, callback) {
var promise = deleteObject(this.s3, this.bucket, this.path + s3Utils.toKey(name));
if (!cb) {
if (!callback) {
return promise;
}
promise.then(function (response) {
cb(undefined, response);
promise.then(function (data) {
callback(null, data);
}, function (reason) {
cb(reason);
callback(reason);
});
};
S3fs.prototype.writeFile = function (name, data, options, cb) {
var callback = cb || (typeof options === 'function' ? options : undefined),
promise = putObject(this.s3, this.bucket, this.path + s3Utils.toKey(name), data, options);
S3fs.prototype.writeFile = function (name, data, options, callback) {
if (typeof options === 'function') {
callback = options;
options = undefined;
}
options = options || {};
if (options.encoding) {
options.ContentEncoding = options.encoding;
delete options.encoding;
}
var promise = putObject(this.s3, this.bucket, this.path + s3Utils.toKey(name), data, options);
if (!callback) {
return promise;
}
promise.then(function (response) {
callback(undefined, response);
promise.then(function (data) {
callback(null, data);
}, function (reason) {

@@ -216,7 +277,7 @@ callback(reason);

S3fs.prototype.clone = function (path) {
return new S3fs(this.s3, s3Utils.joinPaths(this.bucket, s3Utils.joinPaths(this.path, path)));
return new S3fs(s3Utils.joinPaths(this.bucket, s3Utils.joinPaths(this.path, path)), this.s3);
};
/**
* Allows an object to be copied from one path to another path within the same bucket. Paths are relative to
* Allows a file to be copied from one path to another path within the same bucket. Paths are relative to
* the bucket originally provided.

@@ -226,4 +287,4 @@ *

* ```js
* var fsImpl = new S3FS(options, 'test-bucket');
* fsImpl.copyObject('test-folder/test-file.txt', 'other-folder/test-file.txt').then(function() {
* var fsImpl = new S3FS('test-bucket', options);
* fsImpl.copyFile('test-folder/test-file.txt', 'other-folder/test-file.txt').then(function() {
* // Object was successfully copied

@@ -235,27 +296,31 @@ * }, function(reason) {

*
* @param sourcePath `String`. **Required**. Relative path to the source file
* @param destinationPath `String`. **Required**. Relative path to the destination file
* @param cb `Function`. _Optional_. Callback to be used, if not provided will return a Promise
* @param sourceFile `String`. **Required**. Relative path to the source file
* @param destinationFile `String`. **Required**. Relative path to the destination file
* @param callback `Function`. _Optional_. Callback to be used, if not provided will return a Promise
* @returns {Promise|*} Returns a `Promise` if a callback is not provided
*/
S3fs.prototype.copyObject = function (sourcePath, destinationPath, cb) {
var deferred = !cb ? q.defer() : undefined;
if (directoryRegExp.test(sourcePath)) {
// Directories are automatically created, so there's no need to 'copy' a directory.
process.nextTick(function () {
return deferred ? deferred.resolve() : cb(null);
});
} else {
this.s3.copyObject({
Bucket: this.bucket,
Key: this.path + s3Utils.toKey(destinationPath),
CopySource: [this.bucket, this.path + s3Utils.toKey(sourcePath)].join('/')
S3fs.prototype.copyFile = function (sourceFile, destinationFile, callback) {
var self = this;
var promise = new Promise(function (resolve, reject) {
self.s3.copyObject({
Bucket: self.bucket,
Key: self.path + s3Utils.toKey(destinationFile),
CopySource: [self.bucket, self.path + s3Utils.toKey(sourceFile)].join('/')
}, function (err) {
if (err) {
return deferred ? deferred.reject(err + sourcePath) : cb(err + sourcePath);
return reject(err);
}
return deferred ? deferred.resolve() : cb(null);
return resolve();
});
});
if (!callback) {
return promise;
}
return deferred ? deferred.promise : undefined;
promise.then(function () {
callback();
}, function (reason) {
callback(reason);
});
};

@@ -268,3 +333,3 @@

* ```js
* var fsImpl = new S3FS(options, 'test-bucket');
* var fsImpl = new S3FS('test-bucket', options);
* fsImpl.create().then(function() {

@@ -278,20 +343,31 @@ * // Bucket was successfully created

* @param options `Object`. _Optional_. The options to be used when creating the bucket. See [AWS SDK](http://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/S3.html#createBucket-property)
* @param cb `Function`. _Optional_. Callback to be used, if not provided will return a Promise
* @param callback `Function`. _Optional_. Callback to be used, if not provided will return a Promise
* @returns {Promise|*} Returns a `Promise` if a callback is not provided
*/
S3fs.prototype.create = function (options, cb) {
S3fs.prototype.create = function (options, callback) {
if (typeof options === 'function') {
cb = options;
callback = options;
options = undefined;
}
var deferred = !cb ? q.defer() : undefined,
params = extend(true, defaultCreateOptions, options, {Bucket: this.bucket});
this.s3.createBucket(params, function (err, data) {
if (err) {
return deferred ? deferred.reject(err) : cb(err);
}
return deferred ? deferred.resolve(data) : cb(err, data);
var self = this;
var params = extend(true, defaultCreateOptions, options, {Bucket: this.bucket});
var promise = new Promise(function (resolve, reject) {
self.s3.createBucket(params, function (err, data) {
if (err) {
return reject(err);
}
resolve(data);
});
});
return deferred ? deferred.promise : undefined;
if (!callback) {
return promise;
}
promise.then(function () {
callback();
}, function (reason) {
callback(reason);
});
};

@@ -305,3 +381,3 @@

* ```js
* var fsImpl = new S3FS(options, 'test-bucket');
* var fsImpl = new S3FS('test-bucket', options);
* fsImpl.delete().then(function() {

@@ -314,15 +390,25 @@ * // Bucket was successfully deleted

*
* @param cb `Function`. _Optional_. Callback to be used, if not provided will return a Promise
* @param callback `Function`. _Optional_. Callback to be used, if not provided will return a Promise
* @returns {Promise|*} Returns a `Promise` if a callback is not provided
*/
S3fs.prototype.delete = function (cb) {
var deferred = !cb ? q.defer() : undefined,
params = {Bucket: this.bucket};
this.s3.deleteBucket(params, function (err, data) {
if (err) {
return deferred ? deferred.reject(err) : cb(err);
}
return deferred ? deferred.resolve(data) : cb(err, data);
S3fs.prototype.delete = function (callback) {
var self = this;
var promise = new Promise(function (resolve, reject) {
self.s3.deleteBucket({Bucket: self.bucket}, function (err, data) {
if (err) {
return reject(err);
}
resolve(data);
});
});
return deferred ? deferred.promise : undefined;
if (!callback) {
return promise;
}
promise.then(function () {
callback();
}, function (reason) {
callback(reason);
});
};

@@ -335,3 +421,3 @@

* ```js
* var fsImpl = new S3FS(options, 'test-bucket');
* var fsImpl = new S3FS('test-bucket', options);
* fsImpl.headObject('test-file.txt').then(function(details) {

@@ -345,18 +431,29 @@ * // Details contains details such as the `ETag` about the object. See [AWS SDK](http://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/S3.html#headObject-property) for details.

* @param path `String`. **Required**. Path to the object to retrieve the head for
* @param cb `Function`. _Optional_. Callback to be used, if not provided will return a Promise
* @param callback `Function`. _Optional_. Callback to be used, if not provided will return a Promise
* @returns {Promise|*} Returns a `Promise` if a callback is not provided
*/
S3fs.prototype.headObject = function (path, cb) {
S3fs.prototype.headObject = function (path, callback) {
//TODO: Convert the rest of the code to using this method for retrieving the head.
var deferred = !cb ? q.defer() : undefined;
this.s3.headObject({
Bucket: this.bucket,
Key: this.path + s3Utils.toKey(path)
}, function (err, data) {
if (err) {
return deferred ? deferred.reject(err) : cb(err);
}
return deferred ? deferred.resolve(data) : cb(null, data);
var self = this;
var promise = new Promise(function (resolve, reject) {
self.s3.headObject({
Bucket: self.bucket,
Key: self.path + s3Utils.toKey(path)
}, function (err, data) {
if (err) {
return reject(err);
}
resolve(data);
});
});
return deferred ? deferred.promise : undefined;
if (!callback) {
return promise;
}
promise.then(function () {
callback();
}, function (reason) {
callback(reason);
});
};

@@ -370,3 +467,3 @@

* ```js
* var fsImpl = new S3FS(options, 'test-bucket');
* var fsImpl = new S3FS('test-bucket', options);
* fsImpl.listContents('/', '/').then(function(data) {

@@ -381,14 +478,19 @@ * // Data.Contents contains details such as the `ETag` about the object. See [AWS SDK](http://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/S3.html#headObject-property) for details.

* @param marker `String`. **Required**. The key to start with when listing objects
* @param cb `Function`. _Optional_. Callback to be used, if not provided will return a Promise
* @param callback `Function`. _Optional_. Callback to be used, if not provided will return a Promise
* @returns {Promise|*} Returns a `Promise` if a callback is not provided
*/
S3fs.prototype.listContents = function (path, marker, cb) {
var callback = cb || (typeof marker === 'function' ? marker : undefined);
marker = (typeof marker === 'function' ? undefined : marker);
S3fs.prototype.listContents = function (path, marker, callback) {
if (typeof marker === 'function') {
callback = marker;
marker = undefined;
}
var promise = listAllObjects(this.s3, this.bucket, this.path + s3Utils.toKey(path) + '/', '/', marker);
if (!callback) {
return promise;
}
promise.then(function (contents) {
callback(null, contents);
promise.then(function (data) {
callback(null, data);
}, function (reason) {

@@ -408,4 +510,4 @@ callback(reason);

* ```js
* var fsImpl = new S3FS(options, 'test-bucket');
* fsImpl.copyDirectory('test-folder', 'other-folder').then(function() {
* var fsImpl = new S3FS('test-bucket', options);
* fsImpl.copyDir('test-folder', 'other-folder').then(function() {
* // Directory was successfully copied

@@ -419,24 +521,16 @@ * }, function(reason) {

* @param destinationPath `String`. **Required**. The destination directory to be copied to
* @param cb `Function`. _Optional_. Callback to be used, if not provided will return a Promise
* @param callback `Function`. _Optional_. Callback to be used, if not provided will return a Promise
* @returns {Promise|*} Returns a `Promise` if a callback is not provided
*/
S3fs.prototype.copyDirectory = function (sourcePath, destinationPath, cb) {
var self = this,
promise = listAllObjectsFiles(this.s3, this.bucket, this.path + s3Utils.toKey(sourcePath) + '/').then(function (files) {
var deferred = q.defer();
process.nextTick(function () {
var promises = [];
files.forEach(function (file) {
promises.push(self.copyObject([s3Utils.toKey(sourcePath), file].join('/'), [s3Utils.toKey(destinationPath), file].join('/')));
});
q.all(promises).then(function () {
deferred.resolve();
}, function (reason) {
deferred.reject(reason);
});
});
return deferred.promise;
S3fs.prototype.copyDir = function (sourcePath, destinationPath, callback) {
var self = this;
var promise = listAllObjectsFiles(this.s3, this.bucket, this.path + s3Utils.toKey(sourcePath) + '/').then(function (files) {
var promises = [];
files.forEach(function (file) {
promises.push(self.copyFile([s3Utils.toKey(sourcePath), file].join('/'), [s3Utils.toKey(destinationPath), file].join('/')));
});
return Promise.all(promises).return();
});
if (!cb) {
if (!callback) {
return promise;

@@ -446,5 +540,5 @@ }

promise.then(function () {
cb(null);
callback();
}, function (reason) {
cb(reason);
callback(reason);
});

@@ -458,3 +552,3 @@ };

* ```js
* var fsImpl = new S3FS(options, 'test-bucket');
* var fsImpl = new S3FS('test-bucket', options);
* fsImpl.destroy().then(function() {

@@ -467,18 +561,20 @@ * // Bucket was successfully destroyed

*
* @param cb `Function`. _Optional_. Callback to be used, if not provided will return a Promise
* @param callback `Function`. _Optional_. Callback to be used, if not provided will return a Promise
* @returns {Promise|*} Returns a `Promise` if a callback is not provided
*/
S3fs.prototype.destroy = function (cb) {
var deferred = !cb ? q.defer() : undefined,
self = this;
self.rmdirp().then(function () {
self.delete().then(function () {
return deferred ? deferred.resolve() : cb();
}, function (reason) {
return deferred ? deferred.reject(reason) : cb(reason);
});
S3fs.prototype.destroy = function (callback) {
var self = this;
var promise = self.rmdirp().then(function () {
return self.delete();
});
if (!callback) {
return promise;
}
promise.then(function () {
callback();
}, function (reason) {
return deferred ? deferred.reject(reason) : cb(reason);
callback(reason);
});
return deferred ? deferred.promise : undefined;
};

@@ -491,3 +587,3 @@

* ```js
* var fsImpl = new S3FS(options, 'test-bucket');
* var fsImpl = new S3FS('test-bucket', options);
* // Remove the Cached contents in the `/cache` directory each day.

@@ -504,14 +600,16 @@ * fsImpl.putBucketLifecycle('expire cache', 'cache', 1).then(function() {

* @param days Indicates the lifetime, in days, of the objects that are subject to the rule. The value must be a non-zero positive integer.
* @param cb `Function`. _Optional_. Callback to be used, if not provided will return a Promise
* @param callback `Function`. _Optional_. Callback to be used, if not provided will return a Promise
* @returns {Promise|*} Returns a `Promise` if a callback is not provided
*/
S3fs.prototype.putBucketLifecycle = function (name, prefix, days, cb) {
S3fs.prototype.putBucketLifecycle = function (name, prefix, days, callback) {
var promise = putBucketLifecycle(this.s3, this.bucket, name, prefix, days);
if (!cb) {
if (!callback) {
return promise;
}
promise.then(function (response) {
cb(undefined, response);
promise.then(function () {
callback();
}, function (reason) {
cb(reason);
callback(reason);
});

@@ -525,3 +623,3 @@ };

* ```js
* var fsImpl = new S3FS(options, 'test-bucket');
* var fsImpl = new S3FS('test-bucket', options);
* fsImpl.readdirp('test-folder').then(function(files) {

@@ -535,18 +633,20 @@ * // Files contains a list of all of the files similar to [fs.readdir(path, callback)](http://nodejs.org/api/fs.html#fs_fs_readdir_path_callback) but with recursive contents

* @param path `String`. **Required**. The path to the directory to read from
* @param cb `Function`. _Optional_. Callback to be used, if not provided will return a Promise
* @param callback `Function`. _Optional_. Callback to be used, if not provided will return a Promise
* @returns {Promise|*} Returns a `Promise` if a callback is not provided
*/
S3fs.prototype.readdirp = function (path, cb) {
S3fs.prototype.readdirp = function (path, callback) {
var prefix = this.path + s3Utils.toKey(path);
if (prefix[prefix.length - 1] !== '/') {
prefix += '/';
prefix += '/'; // Make sure we have a trailing slash for the directory
}
var promise = listAllObjectsFiles(this.s3, this.bucket, prefix);
if (!cb) {
if (!callback) {
return promise;
}
promise.then(function (files) {
cb(null, files);
promise.then(function (data) {
callback(null, data);
}, function (reason) {
cb(reason);
callback(reason);
});

@@ -560,3 +660,3 @@ };

* ```js
* var fsImpl = new S3FS(options, 'test-bucket');
* var fsImpl = new S3FS('test-bucket', options);
* fsImpl.rmdirp('test-folder').then(function() {

@@ -570,9 +670,9 @@ * // Directory has been recursively deleted

* @param path The path to the directory to delete
* @param cb `Function`. _Optional_. Callback to be used, if not provided will return a Promise
* @param callback `Function`. _Optional_. Callback to be used, if not provided will return a Promise
* @returns {Promise|*} Returns a `Promise` if a callback is not provided
*/
S3fs.prototype.rmdirp = function (path, cb) {
S3fs.prototype.rmdirp = function (path, callback) {
var self = this,
promise = listAllObjectsFiles(this.s3, this.bucket, path ? this.path + s3Utils.toKey(path) + '/' : undefined).then(function (objects) {
return q.all(objects.filter(function (object) {
return Promise.all(objects.filter(function (object) {
//filter items

@@ -591,3 +691,3 @@ return !directoryRegExp.test(object);

if (!cb) {
if (!callback) {
return promise;

@@ -597,5 +697,5 @@ }

promise.then(function () {
cb(null);
callback();
}, function (reason) {
cb(reason);
callback(reason);
});

@@ -616,9 +716,7 @@ };

function getFileStats(s3fs, path, cb) {
var deferred = !cb ? q.defer() : undefined;
// S3 doesn't return information on directories and it automatically creates any that don't exist.
// So we can return semi-static information about the stats of a directory.
if (directoryRegExp.test(path)) {
process.nextTick(function () {
function getFileStats(s3fs, path, callback) {
var promise = new Promise(function (resolve, reject) {
// S3 doesn't return information on directories and it automatically creates any that don't exist.
// So we can return semi-static information about the stats of a directory.
if (directoryRegExp.test(path)) {
var date = new Date(),

@@ -643,35 +741,44 @@ stats = new Stats({

});
return deferred ? deferred.resolve(stats) : cb(null, stats);
});
} else {
s3fs.s3.headObject({
Bucket: s3fs.bucket,
Key: s3fs.path + s3Utils.toKey(path, s3fs.bucket, s3fs.path)
}, function (err, data) {
if (err) {
err.message = err.name;
return deferred ? deferred.reject(err) : cb(err);
}
var stats = new Stats({
dev: 0,
ino: 0,
mode: 0,
nlink: 0,
uid: 0,
gid: 0,
rdev: 0,
size: Number(data.ContentLength),
/* jscs: disable requireCamelCaseOrUpperCaseIdentifiers */
/* jshint camelcase: false */
atim_msec: data.LastModified,
mtim_msec: data.LastModified,
ctim_msec: data.LastModified,
/* jshint camelcase: true */
/* jscs: enable requireCamelCaseOrUpperCaseIdentifiers */
path: path
return resolve(stats);
} else {
s3fs.s3.headObject({
Bucket: s3fs.bucket,
Key: s3fs.path + s3Utils.toKey(path, s3fs.bucket, s3fs.path)
}, function (err, data) {
if (err) {
err.message = err.name;
return reject(err);
}
var stats = new Stats({
dev: 0,
ino: 0,
mode: 0,
nlink: 0,
uid: 0,
gid: 0,
rdev: 0,
size: Number(data.ContentLength),
/* jscs: disable requireCamelCaseOrUpperCaseIdentifiers */
/* jshint camelcase: false */
atim_msec: data.LastModified,
mtim_msec: data.LastModified,
ctim_msec: data.LastModified,
/* jshint camelcase: true */
/* jscs: enable requireCamelCaseOrUpperCaseIdentifiers */
path: path
});
return resolve(stats);
});
return deferred ? deferred.resolve(stats) : cb(err, stats);
});
}
});
if (!callback) {
return promise;
}
return deferred ? deferred.promise : undefined;
promise.then(function (stats) {
callback(null, stats);
}, function (reason) {
callback(reason);
});
}

@@ -688,124 +795,136 @@

function listAllObjects(s3, bucket, prefix, delimiter, marker) {
var deferred = q.defer(),
objectPrefix = prefix === '/' ? undefined : prefix;
s3.listObjects({
Bucket: bucket,
Delimiter: delimiter,
Marker: marker,
Prefix: objectPrefix
}, function (err, data) {
if (err) {
return deferred.reject(err);
}
var contentsList = data.Contents.map(function (item) {
if (objectPrefix && item && item.Key && item.Key.indexOf(objectPrefix) === 0) {
item.Key = item.Key.replace(objectPrefix, '');
var objectPrefix = prefix === '/' ? undefined : prefix;
return new Promise(function (resolve, reject) {
s3.listObjects({
Bucket: bucket,
Delimiter: delimiter,
Marker: marker,
Prefix: objectPrefix
}, function (err, data) {
if (err) {
return reject(err);
}
var contentsList = data.Contents.map(function (item) {
if (objectPrefix && item && item.Key && item.Key.indexOf(objectPrefix) === 0) {
item.Key = item.Key.replace(objectPrefix, '');
}
return item;
}).filter(function (item) {
return item && item.Key;
return item;
}).filter(function (item) {
return item && item.Key;
});
if (data.IsTruncated) {
return listAllObjects(s3, bucket, prefix, delimiter, data.KeyMarker).then(function (contents) {
resolve(contentsList.concat(contents));
}, function (reason) {
reject(reason);
});
}
return resolve(contentsList);
});
});
}
if (data.IsTruncated) {
return listAllObjects(s3, bucket, prefix, delimiter, data.KeyMarker).then(function (contents) {
return deferred.resolve(contentsList.concat(contents));
}, function (reason) {
return deferred.reject(reason);
function listAllObjectsFiles(s3, bucket, prefix, delimiter, marker) {
var objectPrefix = prefix === '/' ? undefined : prefix;
return new Promise(function (resolve, reject) {
s3.listObjects({
Bucket: bucket,
Delimiter: delimiter,
Marker: marker,
Prefix: objectPrefix
}, function (err, data) {
if (err) {
return reject(err);
}
var fileList = data.Contents.map(contentToKey).concat(data.CommonPrefixes.map(contentPrefixesToPrefix)).map(function (item) {
if (objectPrefix && item.indexOf(objectPrefix) === 0) {
return item.replace(objectPrefix, '');
}
return item;
});
}
deferred.resolve(contentsList);
if (data.IsTruncated) {
return listAllObjectsFiles(s3, bucket, prefix, delimiter, data.KeyMarker).then(function (files) {
resolve(fileList.concat(files));
}, function (reason) {
reject(reason);
});
}
resolve(fileList.filter(whiteSpace));
});
});
return deferred.promise;
}
function listAllObjectsFiles(s3, bucket, prefix, delimiter, marker) {
var deferred = q.defer(),
objectPrefix = prefix === '/' ? undefined : prefix;
s3.listObjects({
function getObject(s3, bucket, key, options) {
var s3Options = extend(typeof options === 'object' ? options : {}, {
Bucket: bucket,
Delimiter: delimiter,
Marker: marker,
Prefix: objectPrefix
}, function (err, data) {
if (err) {
return deferred.reject(err);
}
var fileList = data.Contents.map(contentToKey).concat(data.CommonPrefixes.map(contentPrefixesToPrefix)).map(function (item) {
if (objectPrefix && item.indexOf(objectPrefix) === 0) {
return item.replace(objectPrefix, '');
Key: key
});
return new Promise(function (resolve, reject) {
s3.getObject(s3Options, function (err, data) {
if (err) {
return reject(err);
}
return item;
resolve(data);
});
if (data.IsTruncated) {
return listAllObjectsFiles(s3, bucket, prefix, delimiter, data.KeyMarker).then(function (files) {
return deferred.resolve(fileList.concat(files));
}, function (reason) {
return deferred.reject(reason);
});
}
deferred.resolve(fileList.filter(whiteSpace));
});
return deferred.promise;
}
function putObject(s3, bucket, key, body, options) {
var deferred = q.defer(),
s3Options = extend(typeof options === 'object' ? options : {}, {
Bucket: bucket,
Key: key,
Body: body
}); // S3 Put Options: http://docs.aws.amazon.com/AWSJavaScriptSDK/latest/frames.html
s3.putObject(s3Options, function (err, data) {
if (err) {
return deferred.reject(err);
}
deferred.resolve(data);
var s3Options = extend(typeof options === 'object' ? options : {}, {
Bucket: bucket,
Key: key,
Body: body
});
return deferred.promise;
return new Promise(function (resolve, reject) {
s3.putObject(s3Options, function (err, data) {
if (err) {
return reject(err);
}
resolve(data);
});
});
}
function deleteObject(s3, bucket, key) {
var deferred = q.defer();
s3.deleteObject({
Bucket: bucket,
Key: key
}, function (err, data) {
if (err) {
return deferred.reject(err);
}
deferred.resolve(data);
return new Promise(function (resolve, reject) {
s3.deleteObject({
Bucket: bucket,
Key: key
}, function (err, data) {
if (err) {
return reject(err);
}
resolve(data);
});
});
return deferred.promise;
}
function putBucketLifecycle(s3, bucket, name, prefix, days) {
var deferred = q.defer(),
options = {
Bucket: bucket,
LifecycleConfiguration: {
Rules: [
{
Prefix: prefix,
Status: 'Enabled',
Expiration: {
Days: days
},
ID: name
}
]
var options = {
Bucket: bucket,
LifecycleConfiguration: {
Rules: [
{
Prefix: prefix,
Status: 'Enabled',
Expiration: {
Days: days
},
ID: name
}
]
}
};
return new Promise(function (resolve, reject) {
s3.putBucketLifecycle(options, function (err, data) {
if (err) {
reject(err);
} else {
resolve(data);
}
};
s3.putBucketLifecycle(options, function (err, data) {
if (err) {
deferred.reject(err);
} else {
deferred.resolve(data);
}
});
});
return deferred.promise;
}

@@ -819,3 +938,3 @@

}(module, require('./fsInterface'), require('util'), require('q'), require('aws-sdk'), require('./utils'), require('extend'), require('./s3WriteStream'),
}(module, require('./fsInterface'), require('util'), require('bluebird'), require('aws-sdk'), require('./utils'), require('extend'), require('./s3WriteStream'),
require('./Stats')));

@@ -24,3 +24,3 @@ /*

*/
(function (module, Writable, util, extend, q) {
(function (module, Writable, util, extend, Promise) {
'use strict';

@@ -66,6 +66,6 @@

return this.abort().then(function () {
return q.reject(error);
return Promise.reject(error);
}, function () {
// TODO: combine reason with this error
return q.reject(error);
return Promise.reject(error);
});

@@ -75,22 +75,22 @@ }

return this.uploadId().then(function (uploadId) {
var deferred = q.defer();
self.client.uploadPart({
Bucket: self.bucket,
Key: self.key,
Body: buffer,
UploadId: uploadId,
PartNumber: partNumber
}, function (err, result) {
if (err) {
return self.abort().then(function () {
deferred.reject(err);
}, function () {
//TODO: combine the multipart upload error with the abort error
deferred.reject(err);
});
}
result.PartNumber = partNumber;
deferred.resolve(result);
return new Promise(function (resolve, reject) {
self.client.uploadPart({
Bucket: self.bucket,
Key: self.key,
Body: buffer,
UploadId: uploadId,
PartNumber: partNumber
}, function (err, result) {
if (err) {
return self.abort().then(function () {
reject(err);
}, function () {
//TODO: combine the multipart upload error with the abort error
reject(err);
});
}
result.PartNumber = partNumber;
resolve(result);
});
});
return deferred.promise;
});

@@ -102,11 +102,14 @@ };

return this.uploadId().then(function (uploadId) {
var deferred = q.defer();
self.client.abortMultipartUpload({
Bucket: self.bucket,
Key: self.key,
UploadId: uploadId
}, function (err) {
return err ? deferred.reject(err) : deferred.resolve();
return new Promise(function (resolve, reject) {
self.client.abortMultipartUpload({
Bucket: self.bucket,
Key: self.key,
UploadId: uploadId
}, function (err) {
if (err) {
return reject(err);
}
resolve();
});
});
return deferred.promise;
});

@@ -121,13 +124,13 @@ };

this._uploadIdPromise = (function () {
var deferred = q.defer();
self.client.createMultipartUpload({
Bucket: self.bucket,
Key: self.key
}, function (err, data) {
if (err) {
return deferred.reject(err);
}
deferred.resolve(data.UploadId);
return new Promise(function (resolve, reject) {
self.client.createMultipartUpload({
Bucket: self.bucket,
Key: self.key
}, function (err, data) {
if (err) {
return reject(err);
}
resolve(data.UploadId);
});
});
return deferred.promise;
}());

@@ -138,15 +141,15 @@ /* jscs: enable disallowDanglingUnderscores */

MultiPartManager.prototype.put = function () {
var deferred = q.defer(),
self = this;
this.client.putObject({
Bucket: self.bucket,
Key: self.key,
Body: self.currentBuffer
}, function (err, data) {
if (err) {
return deferred.reject(err);
}
deferred.resolve(data);
var self = this;
return new Promise(function (resolve, reject) {
self.client.putObject({
Bucket: self.bucket,
Key: self.key,
Body: self.currentBuffer
}, function (err, data) {
if (err) {
return reject(err);
}
resolve(data);
});
});
return deferred.promise;
};

@@ -158,18 +161,18 @@

self.flush();
return q.all(self.parts).then(function (parts) {
var deferred = q.defer();
self.client.completeMultipartUpload({
Bucket: self.bucket,
Key: self.key,
UploadId: uploadId,
MultipartUpload: {
Parts: parts
}
}, function (err, data) {
if (err) {
return deferred.reject(err);
}
deferred.resolve(data);
return Promise.all(self.parts).then(function (parts) {
return new Promise(function (resolve, reject) {
self.client.completeMultipartUpload({
Bucket: self.bucket,
Key: self.key,
UploadId: uploadId,
MultipartUpload: {
Parts: parts
}
}, function (err, data) {
if (err) {
return reject(err);
}
resolve(data);
});
});
return deferred.promise;
});

@@ -218,2 +221,2 @@ }) : this.put(); //if we did not reach the part limit of 5M just use putObject

module.exports = S3WriteStream;
}(module, require('stream').Writable, require('util'), require('extend'), require('q')));
}(module, require('stream').Writable, require('util'), require('extend'), require('bluebird')));

@@ -36,3 +36,3 @@ /*

function Stats(dev, mode, nlink, uid, gid, rdev, blksize, ino, size, blocks, atim_msec, mtim_msec, ctim_msec, birthtim_msec, path) {
/* jshint maxparams: 4 */
/* jshint maxparams: 4 */
if (arguments.length === 1 && typeof arguments[0] === 'object') {

@@ -39,0 +39,0 @@ return Stats.create(arguments[0]);

{
"name": "s3fs",
"version": "1.1.0",
"description": "Implementation of NodeJS FS interface using Amazon Simple Storage Service (S3).",
"version": "2.0.0",
"description": "Implementation of Node.JS FS interface using Amazon Simple Storage Service (S3).",
"keywords": [

@@ -43,5 +43,4 @@ "s3fs",

"aws-sdk": "^2.x",
"cb-q": "^0.x",
"extend": "^2.x",
"q": "^1.x"
"bluebird": "^2.x",
"extend": "^2.x"
},

@@ -58,9 +57,7 @@ "devDependencies": {

"jshint": "^2.x",
"jsinspect": "^0.x",
"reporter-file": "^1.x"
"jsinspect": "^0.x"
},
"scripts": {
"test": "MOCHA_REPORTER=Spec MOCHA_REPORTER_FILE=reports/xunit.xml istanbul cover node_modules/mocha/bin/_mocha -- --check-leaks --timeout 60000 --reporter reporter-file test/ && jshint --show-non-errors . && jscs . && buddy index.js lib test && nsp audit-package",
"inspect": "jshint --show-non-errors --reporter=jslint . > reports/jshint.xml | echo 'Oh hai' && jscs --reporter checkstyle . > reports/checkstyle.xml | echo 'The name is' && jsinspect . > reports/jsinspect.json | echo 'Bond,' && buddy --reporter json index.js lib test > reports/buddy.json | echo 'James' && nsp audit-package >& reports/security.txt | echo 'Bond.'"
"test": "istanbul cover node_modules/mocha/bin/_mocha -- --check-leaks --timeout 60000 --reporter nyan test/ && jshint --show-non-errors . && jscs . && buddy index.js lib test && nsp audit-package"
}
}

@@ -14,2 +14,4 @@ # S3FS

**Lead Maintainer**: [David Pate](https://github.com/DavidTPate)
## Purpose

@@ -68,6 +70,3 @@ S3FS provides a drop-in replacement for the File System (FS) implementation that is available with Node.JS allowing a distributed file-system to be used

var S3FS = require('s3fs');
var fsImpl = new S3FS({
accessKeyId: XXXXXXXXXXX,
secretAccessKey: XXXXXXXXXXXXXXXXX
}, 'test-bucket');
var fsImpl = new S3FS('test-bucket', options);
fsImpl.writeFile('message.txt', 'Hello Node', function (err) {

@@ -82,6 +81,3 @@ if (err) throw err;

var S3FS = require('s3fs');
var fsImpl = new S3FS({
accessKeyId: XXXXXXXXXXX,
secretAccessKey: XXXXXXXXXXXXXXXXX
}, 'test-bucket');
var fsImpl = new S3FS('test-bucket', options);
fsImpl.writeFile('message.txt', 'Hello Node').then(function() {

@@ -117,3 +113,3 @@ console.log('It\'s saved!');

// Create an instance of S3FS which has a current working directory of `test-folder` within the S3 bucket `test-bucket`
var fsImpl = new S3FS(options, 'test-bucket/test-folder');
var fsImpl = new S3FS('test-bucket/test-folder', options);
// Creates a copy (which uses the same instance of S3FS) which has a current working directory of `test-folder/styles`

@@ -123,14 +119,14 @@ var fsImplStyles = fsImpl.clone('styles');

### s3fs.copyObject(sourcePath, destinationPath, [cb])
Allows an object to be copied from one path to another path within the same bucket. Paths are relative to
### s3fs.copyFile(sourcePath, destinationPath[, callback])
Allows a file to be copied from one path to another path within the same bucket. Paths are relative to
the bucket originally provided.
* sourcePath `String`. **Required**. Relative path to the source file
* destinationPath `String`. **Required**. Relative path to the destination file
* cb `Function`. _Optional_. Callback to be used, if not provided will return a Promise
* sourceFile `String`. **Required**. Relative path to the source file
* destinationFile `String`. **Required**. Relative path to the destination file
* callback `Function`. _Optional_. Callback to be used, if not provided will return a Promise
```js
var fsImpl = new S3FS(options, 'test-bucket');
fsImpl.copyObject('test-folder/test-file.txt', 'other-folder/test-file.txt').then(function() {
// Object was successfully copied
var fsImpl = new S3FS('test-bucket', options);
fsImpl.copyFile('test-folder/test-file.txt', 'other-folder/test-file.txt').then(function() {
// File was successfully copied
}, function(reason) {

@@ -141,3 +137,3 @@ // Something went wrong

### s3fs.copyDirectory(sourcePath, destinationPath, [cb])
### s3fs.copyDir(sourcePath, destinationPath[, callback])
Recursively copies a directory from the source path to the destination path.

@@ -147,7 +143,7 @@

* destinationPath `String`. **Required**. The destination directory to be copied to
* cb `Function`. _Optional_. Callback to be used, if not provided will return a Promise
* callback `Function`. _Optional_. Callback to be used, if not provided will return a Promise
```js
var fsImpl = new S3FS(options, 'test-bucket');
fsImpl.copyDirectory('test-folder', 'other-folder').then(function() {
var fsImpl = new S3FS('test-bucket', options);
fsImpl.copyDir('test-folder', 'other-folder').then(function() {
// Directory was successfully copied

@@ -159,10 +155,10 @@ }, function(reason) {

### s3fs.create(options, [cb])
### s3fs.create(options[, callback])
Creates a new bucket on S3.
* options `Object`. _Optional_. The options to be used when creating the bucket. See [AWS SDK](http://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/S3.html#createBucket-property)
* cb `Function`. _Optional_. Callback to be used, if not provided will return a Promise
* callback `Function`. _Optional_. Callback to be used, if not provided will return a Promise
```js
var fsImpl = new S3FS(options, 'test-bucket');
var fsImpl = new S3FS('test-bucket', options);
fsImpl.create().then(function() {

@@ -175,10 +171,10 @@ // Bucket was successfully created

### s3fs.delete([cb])
### s3fs.delete([callback])
Deletes a bucket on S3, can only be deleted when empty. If you need to delete one that isn't empty use
[`destroy([cb])`](#s3fsdestroycb) instead.
[`destroy([callback])`](#s3fsdestroycallback) instead.
* cb `Function`. _Optional_. Callback to be used, if not provided will return a Promise
* callback `Function`. _Optional_. Callback to be used, if not provided will return a Promise
```js
var fsImpl = new S3FS(options, 'test-bucket');
var fsImpl = new S3FS('test-bucket', options);
fsImpl.delete().then(function() {

@@ -191,9 +187,9 @@ // Bucket was successfully deleted

### s3fs.destroy([cb])
### s3fs.destroy([callback])
Recursively deletes all files within the bucket and then deletes the bucket.
* cb `Function`. _Optional_. Callback to be used, if not provided will return a Promise
* callback `Function`. _Optional_. Callback to be used, if not provided will return a Promise
```js
var fsImpl = new S3FS(options, 'test-bucket');
var fsImpl = new S3FS('test-bucket', options);
fsImpl.destroy().then(function() {

@@ -206,10 +202,10 @@ // Bucket was successfully destroyed

### s3fs.headObject(path, [cb])
### s3fs.headObject(path[, callback])
Retrieves the details about an object, but not the contents.
* path `String`. **Required**. Path to the object to retrieve the head for
* cb `Function`. _Optional_. Callback to be used, if not provided will return a Promise
* callback `Function`. _Optional_. Callback to be used, if not provided will return a Promise
```js
var fsImpl = new S3FS(options, 'test-bucket');
var fsImpl = new S3FS('test-bucket', options);
fsImpl.headObject('test-file.txt').then(function(details) {

@@ -222,4 +218,4 @@ // Details contains details such as the `ETag` about the object. See [AWS SDK](http://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/S3.html#headObject-property) for details.

### s3fs.listContents(path, marker, [cb])
Retrieves a list of all objects within the specific path. The result is similar to that of [`headObject(path, [cb])`](#s3fsheadobjectpath-cb)
### s3fs.listContents(path, marker[, callback])
Retrieves a list of all objects within the specific path. The result is similar to that of [`headObject(path[, callback])`](#s3fsheadobjectpath-callback)
expect that it contains an array of objects.

@@ -229,6 +225,6 @@

* marker `String`. **Required**. The key to start with when listing objects
* cb `Function`. _Optional_. Callback to be used, if not provided will return a Promise
* callback `Function`. _Optional_. Callback to be used, if not provided will return a Promise
```js
var fsImpl = new S3FS(options, 'test-bucket');
var fsImpl = new S3FS('test-bucket', options);
fsImpl.listContents('/', '/').then(function(data) {

@@ -241,3 +237,3 @@ // Data.Contents contains details such as the `ETag` about the object. See [AWS SDK](http://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/S3.html#headObject-property) for details.

### s3fs.putBucketLifecycle(name, prefix, days, [cb])
### s3fs.putBucketLifecycle(name, prefix, days[, callback])
Adds/Updates a lifecycle on a bucket.

@@ -248,6 +244,6 @@

* days Indicates the lifetime, in days, of the objects that are subject to the rule. The value must be a non-zero positive integer.
* cb `Function`. _Optional_. Callback to be used, if not provided will return a Promise
* callback `Function`. _Optional_. Callback to be used, if not provided will return a Promise
```js
mpl = new S3FS(options, 'test-bucket');
var fsImpl = new S3FS(options, 'test-bucket');
// Remove the Cached contents in the `/cache` directory each day.

@@ -261,3 +257,3 @@ fsImpl.putBucketLifecycle('expire cache', 'cache', 1).then(function() {

### s3fs.readdirp(path, [cb])
### s3fs.readdirp(path[, callback])
Recursively reads a directory.

@@ -268,3 +264,3 @@

```js
var fsImpl = new S3FS(options, 'test-bucket');
var fsImpl = new S3FS('test-bucket', options);
fsImpl.readdirp('test-folder').then(function(files) {

@@ -277,10 +273,25 @@ // Files contains a list of all of the files similar to [`fs.readdir(path, callback)`](http://nodejs.org/api/fs.html#fs_fs_readdir_path_callback) but with recursive contents

### s3fs.rmdirp(path, [cb])
### s3fs.mkdirp(path[, callback])
Recursively creates a directory.
* path The path to the directory to create
* callback `Function`. _Optional_. Callback to be used, if not provided will return a Promise
```js
var fsImpl = new S3FS('test-bucket', options);
fsImpl.mkdirp('test-folder').then(function() {
// Directory has been recursively created
}, function(reason) {
// Something went wrong
});
```
### s3fs.rmdirp(path[, callback])
Recursively deletes a directory.
* path The path to the directory to delete
* cb `Function`. _Optional_. Callback to be used, if not provided will return a Promise
* callback `Function`. _Optional_. Callback to be used, if not provided will return a Promise
```js
var fsImpl = new S3FS(options, 'test-bucket');
var fsImpl = new S3FS('test-bucket', options);
fsImpl.rmdirp('test-folder').then(function() {

@@ -322,22 +333,3 @@ // Directory has been recursively deleted

## Code Style
This repository uses [JSHint](https://github.com/jshint/jshint) for static analysis, [JavaScript Code Style](https://github.com/jscs-dev/node-jscs)
for validating code style, [JSInspect](https://github.com/danielstjules/jsinspect) to detect code duplication, [Buddy.js](https://github.com/danielstjules/buddy.js)
to detect the use of [Magic Numbers](http://en.wikipedia.org/wiki/Magic_number_(programming)),
and [Node Security Project](https://github.com/nodesecurity/nsp) for detecting potential security threats with our dependencies.
To run the code quality tools above, simply execute the following command:
```bash
npm run inspect
```
This will create files with the results in the `reports` directory.
## ToDo
* More tests
* More documentation
* Eat more cookies
* Move over to `cb-q` to simplify supporting promises and callbacks
## License

@@ -344,0 +336,0 @@ [MIT](LICENSE)

@@ -24,3 +24,3 @@ /*

*/
(function (chai, chaiAsPromised, cbQ, S3FS) {
(function (chai, chaiAsPromised, Promise, S3FS) {
'use strict';

@@ -50,3 +50,3 @@ var expect = chai.expect;

bucketName = 's3fs-bucket-test-bucket-' + (Math.random() + '').slice(2, 8);
s3fsImpl = new S3FS(s3Credentials, bucketName);
s3fsImpl = new S3FS(bucketName, s3Credentials);
});

@@ -83,3 +83,3 @@

var bucketMaxLength = 64;
s3fsImpl = new S3FS(s3Credentials, new Array(bucketMaxLength).join('asdf'));
s3fsImpl = new S3FS(new Array(bucketMaxLength).join('asdf'), s3Credentials);
return expect(s3fsImpl.create()).to.eventually.be.rejectedWith('asdf');

@@ -93,11 +93,21 @@ });

it('should be able to create a new bucket with a callback', function () {
var cb = cbQ.cb();
s3fsImpl.create(cb);
return expect(cb.promise).to.eventually.be.fulfilled();
return expect(new Promise(function (resolve, reject) {
s3fsImpl.create(function (err) {
if (err) {
return reject(err);
}
resolve();
});
})).to.eventually.be.fulfilled();
});
it('should be able to create a new bucket with options and a callback', function () {
var cb = cbQ.cb();
s3fsImpl.create({}, cb);
return expect(cb.promise).to.eventually.be.fulfilled();
return expect(new Promise(function (resolve, reject) {
s3fsImpl.create({}, function (err) {
if (err) {
return reject(err);
}
resolve();
});
})).to.eventually.be.fulfilled();
});

@@ -116,5 +126,10 @@

.then(function () {
var cb = cbQ.cb();
s3fsImpl.delete(cb);
return cb.promise;
return new Promise(function (resolve, reject) {
s3fsImpl.delete(function (err) {
if (err) {
return reject(err);
}
resolve();
});
});
})

@@ -139,5 +154,10 @@ ).to.eventually.be.fulfilled();

.then(function () {
var cb = cbQ.cb();
s3fsImpl.delete(cb);
return cb.promise;
return new Promise(function (resolve, reject) {
s3fsImpl.delete(function (err) {
if (err) {
return reject(err);
}
resolve();
});
});
});

@@ -157,5 +177,10 @@ })).to.eventually.be.rejectedWith(Error, 'The bucket you tried to delete is not empty');

.then(function () {
var cb = cbQ.cb();
s3fsImpl.destroy(cb);
return cb.promise;
return new Promise(function (resolve, reject) {
s3fsImpl.destroy(function (err) {
if (err) {
return reject(err);
}
resolve();
});
});
})).to.eventually.be.fulfilled();

@@ -210,5 +235,10 @@ });

.then(function () {
var cb = cbQ.cb();
s3fsImpl.readdir('/', cb);
return cb.promise;
return new Promise(function (resolve, reject) {
s3fsImpl.readdir('/', function (err, data) {
if (err) {
return reject(err);
}
resolve(data);
});
});
})

@@ -224,2 +254,2 @@ ).to.eventually.satisfy(function (files) {

});
}(require('chai'), require('chai-as-promised'), require('cb-q'), require('../')));
}(require('chai'), require('chai-as-promised'), require('bluebird'), require('../')));

@@ -24,3 +24,3 @@ /*

*/
(function (chai, chaiAsPromised, dirtyChai, cbQ, S3FS) {
(function (chai, chaiAsPromised, dirtyChai, Promise, S3FS) {
'use strict';

@@ -49,3 +49,3 @@ var expect = chai.expect;

bucketName = 's3fs-directory-test-bucket-' + (Math.random() + '').slice(2, 8);
s3fsImpl = new S3FS(s3Credentials, bucketName);
s3fsImpl = new S3FS(bucketName, s3Credentials);

@@ -73,21 +73,41 @@ return s3fsImpl.create();

it('should be able to create a directory', function () {
return expect(bucketS3fsImpl.mkdir('testDir')).to.eventually.be.fulfilled;
return expect(bucketS3fsImpl.mkdir('testDir')).to.eventually.be.fulfilled();
});
it('should be able to create a directory with a callback', function () {
var cb = cbQ.cb();
bucketS3fsImpl.mkdir('testDir', cb);
return expect(cb.promise).to.eventually.be.fulfilled;
return expect(new Promise(function (resolve, reject) {
s3fsImpl.mkdir('testDir', function (err) {
if (err) {
return reject(err);
}
resolve();
});
})).to.eventually.be.fulfilled();
});
it('should be able to recursively create directories', function () {
return expect(bucketS3fsImpl.mkdirp('testDir/testSubDir/anotherDir')).to.eventually.be.fulfilled();
});
it('should be able to recursively create directories with a callback', function () {
return expect(new Promise(function (resolve, reject) {
s3fsImpl.mkdirp('testDirDos/testSubDir/anotherDir', function (err) {
if (err) {
return reject(err);
}
resolve();
});
})).to.eventually.be.fulfilled();
});
it('should be able to tell that a directory exists', function () {
return expect(bucketS3fsImpl.exists('/')).to.eventually.be.fulfilled;
return expect(bucketS3fsImpl.exists('/')).to.eventually.be.fulfilled();
});
it('should be able to tell that a directory exists with a callback', function () {
var cb = cbQ.cb();
bucketS3fsImpl.exists('/', function (exists) {
cb(null, exists);
});
return expect(cb.promise).to.eventually.be.equal(true);
return expect(new Promise(function (resolve) {
s3fsImpl.exists('/', function (exists) {
resolve(exists);
});
})).to.eventually.be.equal(true);
});

@@ -108,5 +128,7 @@

.then(function () {
var cb = cbQ.cb();
bucketS3fsImpl.exists('testDir/', cb);
return cb.promise;
return new Promise(function (resolve) {
s3fsImpl.exists('testDir/', function (exists) {
resolve(exists);
});
});
})).to.eventually.be.equal(true);

@@ -120,3 +142,3 @@ });

})
).to.eventually.be.fulfilled;
).to.eventually.be.fulfilled();
});

@@ -127,7 +149,12 @@

.then(function () {
var cb = cbQ.cb();
bucketS3fsImpl.rmdir('testDir', cb);
return cb.promise;
return new Promise(function (resolve, reject) {
s3fsImpl.rmdir('testDir', function (err) {
if (err) {
return reject(err);
}
resolve();
});
});
})
).to.eventually.be.fulfilled;
).to.eventually.be.fulfilled();
});

@@ -143,3 +170,3 @@

})
).to.eventually.be.fulfilled;
).to.eventually.be.fulfilled();
});

@@ -153,7 +180,12 @@

.then(function () {
var cb = cbQ.cb();
bucketS3fsImpl.rmdir('testDir', cb);
return cb.promise;
return new Promise(function (resolve, reject) {
s3fsImpl.rmdir('testDir', function (err) {
if (err) {
return reject(err);
}
resolve();
});
});
})
).to.eventually.be.fulfilled;
).to.eventually.be.fulfilled();
});

@@ -167,3 +199,3 @@

.then(function () {
return bucketS3fsImpl.copyDirectory('testDir', 'testCopyDirDestPromise');
return bucketS3fsImpl.copyDir('testDir', 'testCopyDirDestPromise');
})

@@ -187,8 +219,13 @@ .then(function () {

.then(function () {
return bucketS3fsImpl.copyDirectory('testDir', 'testCopyDirDestCb');
return bucketS3fsImpl.copyDir('testDir', 'testCopyDirDestCb');
})
.then(function () {
var cb = cbQ.cb();
bucketS3fsImpl.readdir('testCopyDirDestCb', cb);
return cb.promise;
return new Promise(function (resolve, reject) {
bucketS3fsImpl.readdir('testCopyDirDestCb', function (err, data) {
if (err) {
return reject(err);
}
resolve(data);
});
});
})

@@ -235,5 +272,10 @@ ).to.eventually.satisfy(function (files) {

.then(function () {
var cb = cbQ.cb();
bucketS3fsImpl.readdir('testDir', cb);
return cb.promise;
return new Promise(function (resolve, reject) {
bucketS3fsImpl.readdir('testDir', function (err, data) {
if (err) {
return reject(err);
}
resolve(data);
});
});
});

@@ -270,5 +312,10 @@ })

.then(function () {
var cb = cbQ.cb();
bucketS3fsImpl.readdirp('testDir', cb);
return cb.promise;
return new Promise(function (resolve, reject) {
bucketS3fsImpl.readdirp('testDir', function (err, data) {
if (err) {
return reject(err);
}
resolve(data);
});
});
})

@@ -297,5 +344,10 @@ ).to.eventually.satisfy(function (files) {

.then(function () {
var cb = cbQ.cb();
bucketS3fsImpl.stat('testDir/', cb);
return cb.promise;
return new Promise(function (resolve, reject) {
s3fsImpl.stat('testDir/', function (err, data) {
if (err) {
return reject(err);
}
resolve(data);
});
});
})

@@ -322,5 +374,10 @@ ).to.eventually.satisfy(function (stats) {

.then(function () {
var cb = cbQ.cb();
bucketS3fsImpl.lstat('testDir/', cb);
return cb.promise;
return new Promise(function (resolve, reject) {
bucketS3fsImpl.lstat('testDir/', function (err, data) {
if (err) {
return reject(err);
}
resolve(data);
});
});
})

@@ -361,5 +418,10 @@ ).to.eventually.satisfy(function (stats) {

.then(function () {
var cb = cbQ.cb();
bucketS3fsImpl.readdir('testDir/', cb);
return cb.promise;
return new Promise(function (resolve, reject) {
bucketS3fsImpl.readdir('testDir/', function (err, data) {
if (err) {
return reject(err);
}
resolve(data);
});
});
})

@@ -401,5 +463,10 @@ ).to.eventually.satisfy(function (files) {

.then(function () {
var cb = cbQ.cb();
bucketS3fsImpl.listContents('testDir/', cb);
return cb.promise;
return new Promise(function (resolve, reject) {
bucketS3fsImpl.listContents('testDir/', function (err, data) {
if (err) {
return reject(err);
}
resolve(data);
});
});
})

@@ -414,2 +481,2 @@ ).to.eventually.satisfy(function (files) {

});
}(require('chai'), require('chai-as-promised'), require('dirty-chai'), require('cb-q'), require('../')));
}(require('chai'), require('chai-as-promised'), require('dirty-chai'), require('bluebird'), require('../')));

@@ -24,3 +24,3 @@ /*

*/
(function (chai, chaiAsPromised, fs, cbQ, Q, S3FS) {
(function (chai, chaiAsPromised, fs, Promise, S3FS) {
'use strict';

@@ -48,3 +48,3 @@ var expect = chai.expect;

bucketName = 's3fs-file-test-bucket-' + (Math.random() + '').slice(2, 8);
s3fsImpl = new S3FS(s3Credentials, bucketName);
s3fsImpl = new S3FS(bucketName, s3Credentials);

@@ -76,5 +76,10 @@ return s3fsImpl.create();

it('should be able to write a file from a string with a callback', function () {
var cb = cbQ.cb();
bucketS3fsImpl.writeFile('test.json', '{ "test": "test" }', cb);
return expect(cb.promise).to.eventually.be.fulfilled();
return expect(new Promise(function (resolve, reject) {
bucketS3fsImpl.writeFile('test.json', '{ "test": "test" }', function (err, data) {
if (err) {
return reject(err);
}
resolve(data);
});
})).to.eventually.be.fulfilled();
});

@@ -87,7 +92,23 @@

it('should be able to write a file with encoding', function () {
var fileText = '{ "test": "test" }';
var options = {encoding: 'utf16'};
return bucketS3fsImpl.writeFile('test-file.json', fileText, {encoding: 'utf16'}).then(function () {
return expect(bucketS3fsImpl.readFile('test-file.json', options)).to.eventually.satisfy(function (data) {
expect(data.Body.toString()).to.equal(fileText);
return true;
});
});
});
it('should be able to write a large file with a callback', function () {
var largeFile = fs.readFileSync('./test/mock/large-file.txt'),
cb = cbQ.cb();
bucketS3fsImpl.writeFile('write-large-callback.txt', largeFile, cb);
return expect(cb.promise).to.eventually.be.fulfilled();
var largeFile = fs.readFileSync('./test/mock/large-file.txt');
return expect(new Promise(function (resolve, reject) {
bucketS3fsImpl.writeFile('write-large-callback.txt', largeFile, function (err, data) {
if (err) {
return reject(err);
}
resolve(data);
});
})).to.eventually.be.fulfilled();
});

@@ -106,8 +127,7 @@

.then(function () {
//Cannot use cbQ here since it is not the standard err, data callback signature.
var deferred = Q.defer();
bucketS3fsImpl.exists('test-exists-callback.json', function (exists) {
deferred.resolve(exists);
return new Promise(function (resolve) {
bucketS3fsImpl.exists('test-exists-callback.json', function (exists) {
resolve(exists);
});
});
return deferred.promise;
})

@@ -120,3 +140,3 @@ ).to.eventually.be.equal(true);

.then(function () {
return bucketS3fsImpl.copyObject('test-copy.json', 'test-copy-dos.json');
return bucketS3fsImpl.copyFile('test-copy.json', 'test-copy-dos.json');
})

@@ -129,5 +149,10 @@ ).to.eventually.be.fulfilled();

.then(function () {
var cb = cbQ.cb();
bucketS3fsImpl.copyObject('test-copy-callback.json', 'test-copy-callback-dos.json', cb);
return cb.promise;
return new Promise(function (resolve, reject) {
bucketS3fsImpl.copyFile('test-copy-callback.json', 'test-copy-callback-dos.json', function (err, data) {
if (err) {
return reject(err);
}
resolve(data);
});
});
})

@@ -148,5 +173,10 @@ ).to.eventually.be.fulfilled();

.then(function () {
var cb = cbQ.cb();
bucketS3fsImpl.headObject('test-head-callback.json', cb);
return cb.promise;
return new Promise(function (resolve, reject) {
bucketS3fsImpl.headObject('test-head-callback.json', function (err, data) {
if (err) {
return reject(err);
}
resolve(data);
});
});
})

@@ -167,5 +197,10 @@ ).to.eventually.be.fulfilled();

.then(function () {
var cb = cbQ.cb();
bucketS3fsImpl.unlink('test-delete-callback.json', cb);
return cb.promise;
return new Promise(function (resolve, reject) {
bucketS3fsImpl.unlink('test-delete-callback.json', function (err, data) {
if (err) {
return reject(err);
}
resolve(data);
});
});
})

@@ -180,5 +215,10 @@ ).to.eventually.be.fulfilled();

it('shouldn\'t be able to write a file from an object with a callback', function () {
var cb = cbQ.cb();
bucketS3fsImpl.writeFile('test-write-object.json', {test: 'test'}, cb);
return expect(cb.promise).to.eventually.be.rejectedWith('Expected params.Body to be a string, Buffer, Stream, Blob, or typed array object');
return expect(new Promise(function (resolve, reject) {
bucketS3fsImpl.writeFile('test-write-object.json', {test: 'test'}, function (err, data) {
if (err) {
return reject(err);
}
resolve(data);
});
})).to.eventually.be.rejectedWith('Expected params.Body to be a string, Buffer, Stream, Blob, or typed array object');
});

@@ -192,6 +232,11 @@

it('should be able to write a file from a buffer with a callback', function () {
var exampleFile = fs.readFileSync('./test/mock/example-file.json'),
cb = cbQ.cb();
bucketS3fsImpl.writeFile('test-buffer-callback.json', exampleFile, cb);
return expect(cb.promise).to.eventually.be.fulfilled();
var exampleFile = fs.readFileSync('./test/mock/example-file.json');
return expect(new Promise(function (resolve, reject) {
bucketS3fsImpl.writeFile('test-buffer-callback.json', exampleFile, function (err, data) {
if (err) {
return reject(err);
}
resolve(data);
});
})).to.eventually.be.fulfilled();
});

@@ -205,6 +250,11 @@

it('should be able to write a file from a stream with a callback', function () {
var stream = fs.createReadStream('./test/mock/example-file.json'),
cb = cbQ.cb();
bucketS3fsImpl.writeFile('test-stream-callback.json', stream, cb);
return expect(cb.promise).to.eventually.be.fulfilled();
var stream = fs.createReadStream('./test/mock/example-file.json');
return expect(new Promise(function (resolve, reject) {
bucketS3fsImpl.writeFile('test-stream-callback.json', stream, function (err, data) {
if (err) {
return reject(err);
}
resolve(data);
});
})).to.eventually.be.fulfilled();
});

@@ -218,32 +268,37 @@

it('should be able to write a large file from a stream with a callback', function () {
var stream = fs.createReadStream('./test/mock/large-file.txt'),
cb = cbQ.cb();
bucketS3fsImpl.writeFile('test-large-stream-callback.txt', stream, cb);
return expect(cb.promise).to.eventually.be.fulfilled();
var stream = fs.createReadStream('./test/mock/large-file.txt');
return expect(new Promise(function (resolve, reject) {
bucketS3fsImpl.writeFile('test-large-stream-callback.txt', stream, function (err, data) {
if (err) {
return reject(err);
}
resolve(data);
});
})).to.eventually.be.fulfilled();
});
it('should be able to pipe a file from a stream', function () {
var deferred = Q.defer();
fs.createReadStream('./test/mock/example-file.json')
.pipe(bucketS3fsImpl.createWriteStream('test-pipe.json'))
.on('finish', function () {
deferred.resolve();
})
.on('error', function (err) {
deferred.reject(err);
});
return expect(deferred.promise).to.eventually.be.fulfilled();
return expect(new Promise(function (resolve, reject) {
fs.createReadStream('./test/mock/example-file.json')
.pipe(bucketS3fsImpl.createWriteStream('test-pipe.json'))
.on('finish', function () {
resolve();
})
.on('error', function (err) {
reject(err);
});
})).to.eventually.be.fulfilled();
});
it('should be able to pipe a large file from a stream', function () {
var deferred = Q.defer();
fs.createReadStream('./test/mock/large-file.txt')
.pipe(bucketS3fsImpl.createWriteStream('test-pipe-callback.txt'))
.on('finish', function () {
deferred.resolve();
})
.on('error', function (err) {
deferred.reject(err);
});
return expect(deferred.promise).to.eventually.be.fulfilled();
return expect(new Promise(function (resolve, reject) {
fs.createReadStream('./test/mock/large-file.txt')
.pipe(bucketS3fsImpl.createWriteStream('test-pipe-callback.txt'))
.on('finish', function () {
resolve();
})
.on('error', function (err) {
reject(err);
});
})).to.eventually.be.fulfilled();
});

@@ -258,5 +313,10 @@

//TODO: Get this setup
var cb = cbQ.cb();
bucketS3fsImpl.writeFile('test-blob-callback.json', {test: 'test'}, cb);
return expect(cb.promise).to.eventually.be.fulfilled();
return expect(new Promise(function (resolve, reject) {
bucketS3fsImpl.writeFile('test-blob-callback.json', {test: 'test'}, function (err, data) {
if (err) {
return reject(err);
}
resolve(data);
});
})).to.eventually.be.fulfilled();
});

@@ -271,5 +331,10 @@

//TODO: Get this setup
var cb = cbQ.cb();
bucketS3fsImpl.writeFile('test-typed-callback.json', {test: 'test'}, cb);
return expect(cb.promise).to.eventually.be.fulfilled();
return expect(new Promise(function (resolve, reject) {
bucketS3fsImpl.writeFile('test-blob-callback.json', {test: 'test'}, function (err, data) {
if (err) {
return reject(err);
}
resolve(data);
});
})).to.eventually.be.fulfilled();
});

@@ -280,5 +345,4 @@

.then(function () {
var deferred = Q.defer(),
data = '';
try {
return new Promise(function (resolve, reject) {
var data = '';
bucketS3fsImpl.createReadStream('test-read-stream.json')

@@ -290,11 +354,8 @@ .on('data', function (chunk) {

expect(data).to.be.equal('{ "test": "test" }');
deferred.resolve();
resolve();
})
.on('error', function (err) {
deferred.reject(err);
reject(err);
});
} catch (err) {
deferred.reject(err);
}
return deferred.promise;
});
})

@@ -318,5 +379,10 @@ ).to.eventually.be.fulfilled();

.then(function () {
var cb = cbQ.cb();
bucketS3fsImpl.stat('test-stat-callback.json', cb);
return cb.promise;
return new Promise(function (resolve, reject) {
bucketS3fsImpl.stat('test-stat-callback.json', function (err, data) {
if (err) {
return reject(err);
}
resolve(data);
});
});
})

@@ -334,5 +400,10 @@ ).to.eventually.satisfy(function (stats) {

it('shouldn\'t be able to retrieve the stats of a file that doesn\'t exist with a callback - stat(2)', function () {
var cb = cbQ.cb();
bucketS3fsImpl.stat('test-file-no-exist.json', cb);
return expect(cb.promise).to.eventually.be.rejectedWith(Error, 'NotFound');
return expect(new Promise(function (resolve, reject) {
bucketS3fsImpl.stat('test-file-no-exist.json', function (err, data) {
if (err) {
return reject(err);
}
resolve(data);
});
})).to.eventually.be.rejectedWith(Error, 'NotFound');
});

@@ -354,5 +425,10 @@

.then(function () {
var cb = cbQ.cb();
bucketS3fsImpl.lstat('test-lstat-callback.json', cb);
return cb.promise;
return new Promise(function (resolve, reject) {
bucketS3fsImpl.lstat('test-lstat-callback.json', function (err, data) {
if (err) {
return reject(err);
}
resolve(data);
});
});
})

@@ -366,2 +442,2 @@ ).to.eventually.satisfy(function (stats) {

});
}(require('chai'), require('chai-as-promised'), require('fs'), require('cb-q'), require('q'), require('../')));
}(require('chai'), require('chai-as-promised'), require('fs'), require('bluebird'), require('../')));

@@ -24,3 +24,3 @@ /*

*/
(function (chai, chaiAsPromised, cbQ, S3FS) {
(function (chai, chaiAsPromised, Promise, S3FS) {
'use strict';

@@ -48,3 +48,3 @@ var expect = chai.expect;

bucketName = 's3fs-lifecycle-test-bucket-' + (Math.random() + '').slice(2, 8);
s3fsImpl = new S3FS(s3Credentials, bucketName);
s3fsImpl = new S3FS(bucketName, s3Credentials);

@@ -82,8 +82,14 @@ return s3fsImpl.create();

it('should be able to set a bucket lifecycle with a callback', function () {
var prefix = 'test',
days = 1,
cb = cbQ.cb();
bucketS3fsImpl.putBucketLifecycle('test-lifecycle-callback', prefix, days, cb);
var prefix = 'test';
var days = 1;
//TODO: Add verification that the lifecycle was set
return expect(cb.promise).to.eventually.be.fulfilled();
return expect(new Promise(function (resolve, reject) {
bucketS3fsImpl.putBucketLifecycle('test-lifecycle-callback', prefix, days, function (err, data) {
if (err) {
return reject(err);
}
resolve(data);
});
})).to.eventually.be.fulfilled();
});

@@ -111,5 +117,10 @@

.then(function () {
var cb = cbQ.cb();
s3fsImpl.putBucketLifecycle('test-lifecycle-update-callback', prefix, finalDays, cb);
return cb.promise;
return new Promise(function (resolve, reject) {
bucketS3fsImpl.putBucketLifecycle('test-lifecycle-update-callback', prefix, finalDays, function (err, data) {
if (err) {
return reject(err);
}
resolve(data);
});
});
//TODO: Add verification that the lifecycle was set

@@ -121,2 +132,2 @@ })

});
}(require('chai'), require('chai-as-promised'), require('cb-q'), require('../')));
}(require('chai'), require('chai-as-promised'), require('bluebird'), require('../')));

@@ -24,3 +24,3 @@ /*

*/
(function (chai, chaiAsPromised, fs, cbQ, Q, S3FS) {
(function (chai, chaiAsPromised, S3FS) {
'use strict';

@@ -48,3 +48,3 @@ var expect = chai.expect;

bucketName = 's3fs-clone-test-bucket-' + (Math.random() + '').slice(2, 8);
s3fsImpl = new S3FS(s3Credentials, bucketName);
s3fsImpl = new S3FS(bucketName, s3Credentials);

@@ -71,26 +71,32 @@ return s3fsImpl.create();

it('shouldn\'t be able to instaniate S3FS without options', function () {
it('shouldn\'t be able to instantiate S3FS without a bucket', function () {
return expect(function () {
S3FS();
}).to.throw(Error, 'options is required');
}).to.throw(Error, 'bucket is required');
});
it('shouldn\'t be able to instaniate S3FS without an accessKeyId', function () {
it('shouldn\'t be able to instantiate S3FS with an invalid bucket', function () {
return expect(function () {
S3FS({});
}).to.throw(Error, 'accessKeyId is required');
}).to.throw(Error, 'bucket must be a string');
});
it('shouldn\'t be able to instaniate S3FS without a secretAccessKey', function () {
it('should be able to instantiate S3FS without options', function () {
return expect(function () {
S3FS({accessKeyId: 'test'});
}).to.throw(Error, 'secretAccessKey is required');
S3FS('bucket');
}).to.not.throw();
});
it('shouldn\'t be able to instaniate S3FS without a bucket', function () {
it('shouldn\'t be able to instantiate S3FS without an accessKeyId', function () {
return expect(function () {
S3FS({accessKeyId: 'test', secretAccessKey: 'test'});
}).to.throw(Error, 'bucket is required');
S3FS('bucket', {});
}).to.not.throw();
});
it('shouldn\'t be able to instantiate S3FS without a secretAccessKey', function () {
return expect(function () {
S3FS('bucket', {accessKeyId: 'test'});
}).to.not.throw();
});
it('should be able to clone s3fs', function () {

@@ -113,2 +119,2 @@ return expect(bucketS3fsImpl.clone('imAClone')).to.not.throw;

});
}(require('chai'), require('chai-as-promised'), require('fs'), require('cb-q'), require('q'), require('../')));
}(require('chai'), require('chai-as-promised'), require('../')));

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

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc