Comparing version 6.1.0 to 6.1.1-0.2
## CHANGE LOG | ||
### v6.1.10.1 | ||
2016-05-06 | ||
- npm 通过travis 自动发布 | ||
### v6.1.10 | ||
2016-04-25 | ||
- list 增加delimiter 支持 | ||
- 增加强制copy/move | ||
- 底层使用putReadable 谢谢 @thesadabc | ||
- 修正result 处理 谢谢 @loulin | ||
- fix Unhandled stream error in pipe 谢谢@loulin | ||
- putExtra 修正 paras 为 params | ||
### v6.1.9 | ||
2015-12-03 | ||
- Make secure base url | ||
- policy add fsizeMin | ||
- 修正 getEncodedEntryUri(bucket, key) | ||
- 文档修正 | ||
### v6.1.8 | ||
2015-05-13 | ||
- 上传增加putpolicy2 | ||
### v6.1.7 | ||
2015-05-09 | ||
- 上传putpolicy2增加 callbackHost、persistentPipeline, callbackFetchKey | ||
- 增加fetch 函数 | ||
- imageview -> imageview2 | ||
### v6.1.6 | ||
2014-10-31 | ||
- 上传putpolicy2增加fsizelimit, insertonly | ||
### v6.1.5 | ||
2014-7-23 issue [#111](https://github.com/qiniu/nodejs-sdk/pull/111) | ||
- [#109] 统一user agent | ||
- [#110] 更新put policy | ||
### v6.1.4 | ||
2014-7-10 issue [#108](https://github.com/qiniu/nodejs-sdk/pull/108) | ||
- [#107] 调整上传host | ||
### v6.1.3 | ||
2014-4-03 issue [#102](https://github.com/qiniu/nodejs-sdk/pull/102) | ||
- [#98] 增加pfop 功能 | ||
- [#99] 增加针对七牛callback的检查 | ||
### v6.1.2 | ||
2014-2-17 issue [#96](https://github.com/qiniu/nodejs-sdk/pull/96) | ||
- Content-Length = 0 时的细节修复 | ||
### v6.1.1 | ||
2013-12-5 issue [#90](https://github.com/qiniu/nodejs-sdk/pull/90) | ||
- 创建buffer前检测 | ||
### v6.1.0 | ||
@@ -4,0 +87,0 @@ |
@@ -10,2 +10,4 @@ | ||
conf: require(libpath + '/conf.js'), | ||
rpc: require(libpath + '/rpc.js'), | ||
util: require(libpath + '/util.js') | ||
}; |
{ | ||
"name": "qiniu", | ||
"version": "6.1.0", | ||
"version": "6.1.10.2", | ||
"description": "Node wrapper for Qiniu Resource (Cloud) Storage API", | ||
@@ -11,3 +11,3 @@ "main": "index.js", | ||
"test": "make test", | ||
"blanket": { | ||
"blanket": { | ||
"pattern": "qiniu/qiniu", | ||
@@ -36,3 +36,3 @@ "data-cover-flags": { | ||
], | ||
"author": "qiniutek.com", | ||
"author": "sdk@qiniu.com", | ||
"contributors": [ | ||
@@ -39,0 +39,0 @@ { |
@@ -0,1 +1,4 @@ | ||
var fs = require('fs'); | ||
var path = require('path'); | ||
var os = require('os'); | ||
@@ -5,7 +8,13 @@ exports.ACCESS_KEY = '<PLEASE APPLY YOUR ACCESS KEY>'; | ||
exports.USER_AGENT = 'qiniu nodejs-sdk v6.0.0'; | ||
var pkg = JSON.parse(fs.readFileSync(path.join(__dirname, '../', 'package.json'))); | ||
var ua = function() { | ||
return 'QiniuNodejs/' + pkg.version + ' (' + os.type() + '; ' + os.platform() + '; ' + os.arch() + '; )'; | ||
} | ||
exports.UP_HOST = 'http://up.qbox.me'; | ||
exports.USER_AGENT = ua(); | ||
exports.UP_HOST = 'http://upload.qiniu.com'; | ||
exports.RS_HOST = 'http://rs.qbox.me'; | ||
exports.RSF_HOST = 'http://rsf.qbox.me'; | ||
exports.RPC_TIMEOUT = 3600000; // default rpc timeout: one hour | ||
exports.API_HOST = 'http://api.qiniu.com'; | ||
exports.RPC_TIMEOUT = 3600000; // default rpc timeout: one hour |
@@ -0,2 +1,6 @@ | ||
var util = require('./util'); | ||
var rpc = require('./rpc'); | ||
var conf = require('./conf'); | ||
var querystring = require('querystring'); | ||
@@ -6,2 +10,3 @@ exports.ImageView = ImageView; | ||
exports.Exif = Exif; | ||
exports.pfop = pfop; | ||
@@ -17,3 +22,3 @@ function ImageView(mode, width, height, quality, format) { | ||
ImageView.prototype.makeRequest = function(url) { | ||
url += '?imageView/' + this.mode; | ||
url += '?imageView2/' + this.mode; | ||
@@ -39,4 +44,3 @@ if (this.width > 0) { | ||
function ImageInfo() { | ||
} | ||
function ImageInfo() {} | ||
@@ -47,4 +51,3 @@ ImageInfo.prototype.makeRequest = function(url) { | ||
function Exif() { | ||
} | ||
function Exif() {} | ||
@@ -56,1 +59,27 @@ Exif.prototype.makeRequest = function(url) { | ||
function pfop(bucket, key, fops, opts, onret) { | ||
opts = opts || {}; | ||
param = { | ||
bucket: bucket, | ||
key: key, | ||
fops: fops | ||
}; | ||
if (opts.notifyURL) { | ||
param.notifyURL = opts.notifyURL; | ||
} else { | ||
param.notifyURL = 'www.test.com'; | ||
} | ||
if (opts.force) { | ||
param.force = 1; | ||
} | ||
if (opts.pipeline) { | ||
param.pipeline = opts.pipeline; | ||
} | ||
var uri = conf.API_HOST + '/pfop/'; | ||
var body = querystring.stringify(param); | ||
var auth = util.generateAccessToken(uri, body); | ||
rpc.postWithForm(uri, body, auth, onret); | ||
} |
@@ -8,2 +8,3 @@ var conf = require('./conf'); | ||
var mime = require('mime'); | ||
var Readable = require('stream').Readable; | ||
var formstream = require('formstream'); | ||
@@ -17,2 +18,3 @@ | ||
exports.putFile = putFile; | ||
exports.putReadable = putReadable; | ||
exports.putFileWithoutKey = putFileWithoutKey; | ||
@@ -22,3 +24,3 @@ | ||
function PutExtra(params, mimeType, crc32, checkCrc) { | ||
this.paras = params || {}; | ||
this.params = params || {}; | ||
this.mimeType = mimeType || null; | ||
@@ -33,6 +35,6 @@ this.crc32 = crc32 || null; | ||
this.key = key || null; | ||
} | ||
} | ||
// onret: callback function instead of ret | ||
function put(uptoken, key, body, extra, onret) { | ||
// onret: callback function instead of ret | ||
function putReadable (uptoken, key, rs, extra, onret) { | ||
if(!extra) { | ||
@@ -49,12 +51,31 @@ extra = new PutExtra(); | ||
var form = getMultipart(uptoken, key, body, extra); | ||
rs.on("error", function (err) { | ||
onret({code: -1, error: err.toString()}, {}); | ||
}); | ||
var form = getMultipart(uptoken, key, rs, extra); | ||
rpc.postMultipart(conf.UP_HOST, form, onret); | ||
return rpc.postMultipart(conf.UP_HOST, form, onret); | ||
} | ||
function put(uptoken, key, body, extra, onret) { | ||
var rs = new Readable(); | ||
rs.push(body); | ||
rs.push(null); | ||
if(!extra) { | ||
extra = new PutExtra(); | ||
} | ||
if (extra.checkCrc == 1) { | ||
var bodyCrc32 = getCrc32(body); | ||
extra.crc32 = '' + parseInt(bodyCrc32, 16); | ||
} | ||
return putReadable(uptoken, key, rs, extra, onret) | ||
} | ||
function putWithoutKey(uptoken, body, extra, onret) { | ||
put(uptoken, null, body, extra, onret); | ||
return put(uptoken, null, body, extra, onret); | ||
} | ||
function getMultipart(uptoken, key, body, extra) { | ||
function getMultipart(uptoken, key, rs, extra) { | ||
@@ -67,15 +88,4 @@ var form = formstream(); | ||
} | ||
form.stream('file', rs, key, extra.mimeType); | ||
form.buffer('file', new Buffer(body), key, extra.mimeType); | ||
//extra['checkcrc'] | ||
if (extra.checkCrc == 1) { | ||
var bodyCrc32 = getCrc32(body); | ||
extra.crc32 = '' + parseInt(bodyCrc32, 16); | ||
} | ||
if(extra.checkCrc) { | ||
form.field('crc32', extra.crc32); | ||
} | ||
for (var k in extra.params) { | ||
@@ -89,22 +99,21 @@ form.field(k, extra.params[k]); | ||
function putFile(uptoken, key, loadFile, extra, onret) { | ||
fs.readFile(loadFile, function(err, data) { | ||
if(err) { | ||
onret({code: -1, error: err.toString()}, {}); | ||
return; | ||
} | ||
if(!extra) { | ||
extra = new PutExtra(); | ||
} | ||
var rs = fs.createReadStream(loadFile); | ||
if(!extra.mimeType) { | ||
extra.mimeType = mime.lookup(loadFile); | ||
} | ||
put(uptoken, key, data, extra, onret); | ||
}); | ||
if(!extra) { | ||
extra = new PutExtra(); | ||
} | ||
if (extra.checkCrc == 1) { | ||
var fileCrc32 = getCrc32(fs.readFileSync(loadFile)); | ||
extra.crc32 = '' + parseInt(fileCrc32, 16); | ||
} | ||
if(!extra.mimeType) { | ||
extra.mimeType = mime.lookup(loadFile); | ||
} | ||
return putReadable(uptoken, key, rs, extra, onret); | ||
} | ||
function putFileWithoutKey(uptoken, loadFile, extra, onret) { | ||
putFile(uptoken, null, loadFile, extra, onret); | ||
return putFile(uptoken, null, loadFile, extra, onret); | ||
} | ||
@@ -10,3 +10,3 @@ var urllib = require('urllib'); | ||
function postMultipart(uri, form, onret) { | ||
post(uri, form, form.headers(), onret); | ||
return post(uri, form, form.headers(), onret); | ||
} | ||
@@ -21,3 +21,3 @@ | ||
} | ||
post(uri, form, headers, onret); | ||
return post(uri, form, headers, onret); | ||
} | ||
@@ -32,3 +32,3 @@ | ||
} | ||
post(uri, null, headers, onret); | ||
return post(uri, null, headers, onret); | ||
} | ||
@@ -40,25 +40,27 @@ | ||
var content = null; | ||
if (Buffer.isBuffer(form) || typeof form === 'string') { | ||
content = form; | ||
form = null; | ||
} | ||
var req = urllib.request(uri, { | ||
var data = { | ||
headers: headers, | ||
method: 'POST', | ||
content: content, | ||
dataType: 'json', | ||
timeout: conf.RPC_TIMEOUT, | ||
}, function (err, result, res) { | ||
if (err) { | ||
err.code = res && res.statusCode || -1; | ||
}; | ||
if (Buffer.isBuffer(form) || typeof form === 'string') { | ||
data.content = form; | ||
} else if (form) { | ||
data.stream = form; | ||
} else { | ||
data.headers['Content-Length'] = 0; | ||
}; | ||
var req = urllib.request(uri, data, function(err, result, res) { | ||
var rerr = null; | ||
if (err || Math.floor(res.statusCode/100) !== 2) { | ||
rerr = {code: res&&res.statusCode||-1, error: err||result&&result.error||''}; | ||
} | ||
onresp(err, result, res); | ||
onresp(rerr, result, res); | ||
}); | ||
if (form) { | ||
form.pipe(req); | ||
} | ||
return req; | ||
} | ||
167
qiniu/rs.js
@@ -1,2 +0,1 @@ | ||
var url = require('url'); | ||
@@ -20,2 +19,3 @@ var crypto = require('crypto'); | ||
exports.PutPolicy = PutPolicy; | ||
exports.PutPolicy2 = PutPolicy2; | ||
exports.GetPolicy = GetPolicy; | ||
@@ -54,2 +54,12 @@ exports.makeBaseUrl = makeBaseUrl; | ||
Client.prototype.forceMove = function(bucketSrc, keySrc, bucketDest, keyDest, force, onret) { | ||
var encodedEntryURISrc = getEncodedEntryUri(bucketSrc, keySrc); | ||
var encodedEntryURIDest = getEncodedEntryUri(bucketDest, keyDest); | ||
var uri = conf.RS_HOST + '/move/' + encodedEntryURISrc + '/' + encodedEntryURIDest +'/force/'+force; | ||
var digest = util.generateAccessToken(uri, null); | ||
rpc.postWithoutForm(uri, digest, onret); | ||
} | ||
Client.prototype.copy = function(bucketSrc, keySrc, bucketDest, keyDest, onret) { | ||
@@ -59,2 +69,3 @@ var encodedEntryURISrc = getEncodedEntryUri(bucketSrc, keySrc); | ||
var uri = conf.RS_HOST + '/copy/' + encodedEntryURISrc + '/' + encodedEntryURIDest; | ||
var digest = util.generateAccessToken(uri, null); | ||
@@ -64,3 +75,21 @@ rpc.postWithoutForm(uri, digest, onret); | ||
Client.prototype.forceCopy = function(bucketSrc, keySrc, bucketDest, keyDest, force, onret) { | ||
var encodedEntryURISrc = getEncodedEntryUri(bucketSrc, keySrc); | ||
var encodedEntryURIDest = getEncodedEntryUri(bucketDest, keyDest); | ||
var uri = conf.RS_HOST + '/copy/' + encodedEntryURISrc + '/' + encodedEntryURIDest +'/force/'+force; | ||
var digest = util.generateAccessToken(uri, null); | ||
rpc.postWithoutForm(uri, digest, onret); | ||
} | ||
Client.prototype.fetch = function(url, bucket, key, onret) { | ||
var bucketUri = getEncodedEntryUri(bucket, key); | ||
var fetchUrl = util.urlsafeBase64Encode(url); | ||
var uri = 'http://iovip.qbox.me/fetch/' + fetchUrl + '/to/' + bucketUri; | ||
var digest = util.generateAccessToken(uri, null); | ||
rpc.postWithoutForm(uri, digest, onret); | ||
} | ||
function Entry(hash, fsize, putTime, mimeType, endUser) { | ||
@@ -94,4 +123,11 @@ this.hash = hash || null; | ||
EntryPathPair.prototype.toStr = function(op) { | ||
return 'op=/' + op + '/' + this.src.encode() + '/' + this.dest.encode() + '&'; | ||
EntryPathPair.prototype.toStr = function(op, force) { | ||
if(typeof(force)=='undefined'){ | ||
return 'op=/' + op + '/' + this.src.encode() + '/' + this.dest.encode() + '&'; | ||
}else{ | ||
return 'op=/' + op + '/' + this.src.encode() + '/' + this.dest.encode() + '/force/' + force + '&'; | ||
} | ||
} | ||
@@ -122,2 +158,8 @@ | ||
Client.prototype.forceBatchMove = function(entries, force, onret) { | ||
fileHandleForce('move', entries, force, onret); | ||
} | ||
Client.prototype.batchCopy = function(entries, onret) { | ||
@@ -127,2 +169,9 @@ fileHandle('copy', entries, onret); | ||
Client.prototype.forceBatchCopy = function(entries, force, onret) { | ||
fileHandleForce('copy', entries, force, onret); | ||
} | ||
function fileHandle(op, entries, onret) { | ||
@@ -139,4 +188,16 @@ var body = ''; | ||
function fileHandleForce(op, entries, force, onret) { | ||
var body = ''; | ||
for (var i in entries) { | ||
body += entries[i].toStr(op, force); | ||
} | ||
console.log(body); | ||
var uri = conf.RS_HOST + '/batch'; | ||
var digest = util.generateAccessToken(uri, body); | ||
rpc.postWithForm(uri, body, digest, onret); | ||
} | ||
function getEncodedEntryUri(bucket, key) { | ||
return util.urlsafeBase64Encode(bucket + ':' + key); | ||
return util.urlsafeBase64Encode(bucket + (key ? ':' + key : '')); | ||
} | ||
@@ -146,4 +207,3 @@ | ||
// @gist PutPolicy | ||
function PutPolicy(scope, callbackUrl, callbackBody, returnUrl, returnBody, | ||
asyncOps, endUser, expires) { | ||
function PutPolicy(scope, callbackUrl, callbackBody, returnUrl, returnBody, endUser, expires, persistentOps, persistentNotifyUrl) { | ||
this.scope = scope || null; | ||
@@ -154,5 +214,6 @@ this.callbackUrl = callbackUrl || null; | ||
this.returnBody = returnBody || null; | ||
this.asyncOps = asyncOps || null; | ||
this.endUser = endUser || null; | ||
this.expires = expires || 3600; | ||
this.persistentOps = persistentOps || null; | ||
this.persistentNotifyUrl = persistentNotifyUrl || null; | ||
} | ||
@@ -173,30 +234,78 @@ // @endgist | ||
PutPolicy.prototype.getFlags = function(putPolicy) { | ||
PutPolicy.prototype.getFlags = function() { | ||
var flags = {}; | ||
if (this.scope != null) { | ||
flags['scope'] = this.scope; | ||
var attrs = ['scope', 'insertOnly', 'saveKey', 'endUser', 'returnUrl', 'returnBody', 'callbackUrl', 'callbackHost', 'callbackBody', 'callbackBodyType', 'callbackFetchKey', 'persistentOps', 'persistentNotifyUrl', 'persistentPipeline', 'fsizeLimit', 'detectMime', 'mimeLimit']; | ||
for (var i = attrs.length - 1; i >= 0; i--) { | ||
if (this[attrs[i]] !== null) { | ||
flags[attrs[i]] = this[attrs[i]]; | ||
} | ||
} | ||
if (this.callbackUrl != null) { | ||
flags['callbackUrl'] = this.callbackUrl; | ||
flags['deadline'] = this.expires + Math.floor(Date.now() / 1000); | ||
return flags; | ||
} | ||
function PutPolicy2(putPolicyObj) { | ||
if (typeof putPolicyObj !== 'object') { | ||
return false; | ||
} | ||
if (this.callbackBody != null) { | ||
flags['callbackBody'] = this.callbackBody; | ||
this.scope = putPolicyObj.scope || null; | ||
this.expires = putPolicyObj.expires || 3600; | ||
this.insertOnly = putPolicyObj.insertOnly || null; | ||
this.saveKey = putPolicyObj.saveKey || null; | ||
this.endUser = putPolicyObj.endUser || null; | ||
this.returnUrl = putPolicyObj.returnUrl || null; | ||
this.returnBody = putPolicyObj.returnBody || null; | ||
this.callbackUrl = putPolicyObj.callbackUrl || null; | ||
this.callbackHost = putPolicyObj.callbackHost || null; | ||
this.callbackBody = putPolicyObj.callbackBody || null; | ||
this.callbackBodyType = putPolicyObj.callbackBodyType || null; | ||
this.persistentOps = putPolicyObj.persistentOps || null; | ||
this.persistentNotifyUrl = putPolicyObj.persistentNotifyUrl || null; | ||
this.persistentPipeline = putPolicyObj.persistentPipeline || null; | ||
this.fsizeLimit = putPolicyObj.fsizeLimit || null; | ||
this.fsizeMin = putPolicyObj.fsizeMin || null; | ||
this.detectMime = putPolicyObj.detectMime || null; | ||
this.mimeLimit = putPolicyObj.mimeLimit || null; | ||
} | ||
PutPolicy2.prototype.token = function(mac) { | ||
if (mac == null) { | ||
mac = new Mac(conf.ACCESS_KEY, conf.SECRET_KEY); | ||
} | ||
if (this.returnUrl != null) { | ||
flags['returnUrl'] = this.returnUrl; | ||
var flags = this.getFlags(); | ||
var encodedFlags = util.urlsafeBase64Encode(JSON.stringify(flags)); | ||
var encoded = util.hmacSha1(encodedFlags, mac.secretKey); | ||
var encodedSign = util.base64ToUrlSafe(encoded); | ||
var uploadToken = mac.accessKey + ':' + encodedSign + ':' + encodedFlags; | ||
return uploadToken; | ||
} | ||
PutPolicy2.prototype.getFlags = function() { | ||
var flags = {}; | ||
var attrs = ['scope', 'insertOnly', 'saveKey', 'endUser', 'returnUrl', 'returnBody', 'callbackUrl', 'callbackHost', 'callbackBody', 'callbackBodyType', 'callbackFetchKey', 'persistentOps', 'persistentNotifyUrl', 'persistentPipeline', 'fsizeLimit','fsizeMin', 'detectMime', 'mimeLimit']; | ||
for (var i = attrs.length - 1; i >= 0; i--) { | ||
if (this[attrs[i]] !== null) { | ||
flags[attrs[i]] = this[attrs[i]]; | ||
} | ||
} | ||
if (this.returnBody != null) { | ||
flags['returnBody'] = this.returnBody; | ||
} | ||
if (this.asyncOps != null) { | ||
flags['asyncOps'] = this.asyncOps; | ||
} | ||
if (this.endUser != null) { | ||
flags['endUser'] = this.endUser; | ||
} | ||
flags['deadline'] = this.expires + Math.floor(Date.now() / 1000); | ||
return flags; | ||
} | ||
function GetPolicy(expires) { | ||
@@ -227,5 +336,7 @@ this.expires = expires || 3600; | ||
function makeBaseUrl(domain, key) { | ||
// domain maybe 'http://hello.qiniu.com', 'https://hello.qiniu.com' and 'hello.qiniu.com' | ||
// query like '-thumbnail', '?imageMogr2/thumbnail/960x' and so on | ||
function makeBaseUrl(domain, key, query) { | ||
key = new Buffer(key); | ||
return 'http://' + domain + '/' + querystring.escape(key); | ||
return (/^https?:\/\//.test(domain) ? domain : 'http://' + domain) + '/' + querystring.escape(key) + (query || ''); | ||
} |
@@ -5,4 +5,4 @@ var rpc = require('./rpc'); | ||
exports.listPrefix = function(bucket, prefix, marker, limit, onret) { | ||
var uri = getPrefixUri(bucket, prefix, marker, limit); | ||
exports.listPrefix = function(bucket, prefix, marker, limit, delimiter, onret) { | ||
var uri = getPrefixUri(bucket, prefix, marker, limit, delimiter); | ||
var digest = util.generateAccessToken(uri, null); | ||
@@ -13,3 +13,3 @@ | ||
function getPrefixUri(bucket, prefix, marker, limit) { | ||
function getPrefixUri(bucket, prefix, marker, limit, delimiter) { | ||
var uri = conf.RSF_HOST + '/' + 'list?' + 'bucket=' + bucket; | ||
@@ -27,2 +27,7 @@ if (marker) { | ||
} | ||
if(delimiter){ | ||
uri += '&' + 'delimiter=' + delimiter; | ||
} | ||
return uri; | ||
@@ -29,0 +34,0 @@ } |
@@ -7,2 +7,4 @@ var fs = require('fs'); | ||
exports.isQiniuCallback = isQiniuCallback; | ||
// ------------------------------------------------------------------------------------------ | ||
@@ -45,1 +47,6 @@ // func encode | ||
} | ||
function isQiniuCallback(path, body, callbackAuth) { | ||
var auth = exports.generateAccessToken(path, body); | ||
return auth === callbackAuth; | ||
} |
# Qiniu Resource Storage SDK for Node.js | ||
[![Build Status](https://travis-ci.org/qiniu/nodejs-sdk.png?branch=master)](https://travis-ci.org/qiniu/nodejs-sdk) | ||
[![@qiniu on weibo](http://img.shields.io/badge/weibo-%40qiniutek-blue.svg)](http://weibo.com/qiniutek) | ||
[![Software License](https://img.shields.io/badge/license-MIT-brightgreen.svg)](LICENSE.md) | ||
[![Build Status](https://travis-ci.org/qiniu/nodejs-sdk.v6.png?branch=master)](https://travis-ci.org/qiniu/nodejs-sdk.v6) | ||
[![Code Climate](https://codeclimate.com/github/qiniu/nodejs-sdk.png)](https://codeclimate.com/github/qiniu/nodejs-sdk) | ||
[![Latest Stable Version](https://img.shields.io/npm/v/qiniu.svg)](https://www.npmjs.com/package/qiniu) | ||
[![Qiniu Logo](http://qiniutek.com/images/logo-2.png)](http://qiniu.com/) | ||
## 下载 | ||
@@ -21,14 +23,12 @@ | ||
这里可以下载到旧版本的SDK,release 版本有版本号,有 [CHANGELOG](https://github.com/qiniu/nodejs-sdk/blob/develop/CHANGELOG.md),使用规格也会比较稳定。 | ||
这里可以下载到旧版本的SDK,release 版本有版本号,有 [CHANGELOG](https://github.com/qiniu/nodejs-sdk/blob/master/CHANGELOG.md),使用规格也会比较稳定。 | ||
### 从 git 库下载 | ||
你可以直接用 git clone 下载源代码来使用。但是请注意非 master 分支的代码在规格上可能承受变更,应谨慎使用。 | ||
你可以直接用 git clone 下载源代码来使用。但是请注意非 master 分支的代码可能会变更,应谨慎使用。 | ||
## 使用 | ||
参考文档:[七牛云存储 Node.js SDK 使用指南](https://github.com/qiniu/nodejs-sdk/tree/develop/docs) | ||
参考文档:[七牛云存储 Node.js SDK 使用指南](http://developer.qiniu.com/docs/v6/sdk/nodejs-sdk.html) | ||
旧版本的SDK(version < 6.0.0) [戳这里](http://docs.qiniutek.com/v3/sdk/nodejs/) | ||
## 贡献代码 | ||
@@ -44,3 +44,3 @@ | ||
Copyright (c) 2013 qiniu.com | ||
Copyright (c) 2015 qiniu.com | ||
@@ -47,0 +47,0 @@ 基于 MIT 协议发布: |
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
Manifest confusion
Supply chain riskThis package has inconsistent metadata. This could be malicious or caused by an error when publishing the package.
Found 1 instance in 1 package
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
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
30616
14
592
2
11
1