Socket
Socket
Sign inDemoInstall

gcs-resumable-upload

Package Overview
Dependencies
Maintainers
9
Versions
68
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

gcs-resumable-upload - npm Package Compare versions

Comparing version 0.13.0 to 0.14.0

6

build/src/index.d.ts

@@ -11,2 +11,5 @@ /**

import * as Pumpify from 'pumpify';
export interface ErrorWithCode extends Error {
code: number;
}
export declare type CreateUriCallback = (err: Error | null, uri?: string) => void;

@@ -125,3 +128,5 @@ export interface Encryption {

constructor(cfg: UploadConfig);
createURI(): Promise<string>;
createURI(callback: CreateUriCallback): void;
protected createURIAsync(): Promise<string>;
private continueUploading;

@@ -143,2 +148,3 @@ private startUploading;

export declare function upload(cfg: UploadConfig): Upload;
export declare function createURI(cfg: UploadConfig): Promise<string>;
export declare function createURI(cfg: UploadConfig, callback: CreateUriCallback): void;

275

build/src/index.js

@@ -8,2 +8,10 @@ "use strict";

*/
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", { value: true });

@@ -22,5 +30,2 @@ const ConfigStore = require("configstore");

const RETRY_LIMIT = 5;
const wrapError = (message, err) => {
return new Error([message, err.message].join('\n'));
};
class Upload extends Pumpify {

@@ -31,3 +36,3 @@ constructor(cfg) {

this.numRetries = 0;
streamEvents.call(this);
streamEvents(this);
cfg = cfg || {};

@@ -88,32 +93,37 @@ if (!cfg.bucket || !cfg.file) {

createURI(callback) {
const metadata = this.metadata;
const reqOpts = {
method: 'POST',
url: [BASE_URI, this.bucket, 'o'].join('/'),
params: { name: this.file, uploadType: 'resumable' },
data: metadata,
headers: {}
};
if (metadata.contentLength) {
reqOpts.headers['X-Upload-Content-Length'] = metadata.contentLength;
if (!callback) {
return this.createURIAsync();
}
if (metadata.contentType) {
reqOpts.headers['X-Upload-Content-Type'] = metadata.contentType;
}
if (typeof this.generation !== 'undefined') {
reqOpts.params.ifGenerationMatch = this.generation;
}
if (this.kmsKeyName) {
reqOpts.params.kmsKeyName = this.kmsKeyName;
}
if (this.predefinedAcl) {
reqOpts.params.predefinedAcl = this.predefinedAcl;
}
if (this.origin) {
reqOpts.headers.Origin = this.origin;
}
this.makeRequest(reqOpts, (err, resp) => {
if (err) {
return callback(err);
this.createURIAsync().then(r => callback(null, r), callback);
}
createURIAsync() {
return __awaiter(this, void 0, void 0, function* () {
const metadata = this.metadata;
const reqOpts = {
method: 'POST',
url: [BASE_URI, this.bucket, 'o'].join('/'),
params: { name: this.file, uploadType: 'resumable' },
data: metadata,
headers: {}
};
if (metadata.contentLength) {
reqOpts.headers['X-Upload-Content-Length'] =
metadata.contentLength.toString();
}
if (metadata.contentType) {
reqOpts.headers['X-Upload-Content-Type'] = metadata.contentType;
}
if (typeof this.generation !== 'undefined') {
reqOpts.params.ifGenerationMatch = this.generation;
}
if (this.kmsKeyName) {
reqOpts.params.kmsKeyName = this.kmsKeyName;
}
if (this.predefinedAcl) {
reqOpts.params.predefinedAcl = this.predefinedAcl;
}
if (this.origin) {
reqOpts.headers.Origin = this.origin;
}
const resp = yield this.makeRequest(reqOpts);
const uri = resp.headers.location;

@@ -123,24 +133,29 @@ this.uri = uri;

this.offset = 0;
callback(null, uri);
return uri;
});
}
continueUploading() {
if (typeof this.offset === 'number') {
return this.startUploading();
}
this.getAndSetOffset(this.startUploading.bind(this));
return __awaiter(this, void 0, void 0, function* () {
if (typeof this.offset === 'number') {
this.startUploading();
return;
}
yield this.getAndSetOffset();
this.startUploading();
});
}
startUploading() {
const reqOpts = {
method: 'PUT',
url: this.uri,
headers: {
'Content-Range': 'bytes ' + this.offset + '-*/' + this.contentLength
}
};
const bufferStream = this.bufferStream = new stream_1.PassThrough();
const offsetStream = this.offsetStream =
new stream_1.PassThrough({ transform: this.onChunk.bind(this) });
const delayStream = new stream_1.PassThrough();
this.getRequestStream(reqOpts, (requestStream) => {
return __awaiter(this, void 0, void 0, function* () {
const reqOpts = {
method: 'PUT',
url: this.uri,
headers: {
'Content-Range': 'bytes ' + this.offset + '-*/' + this.contentLength
}
};
const bufferStream = this.bufferStream = new stream_1.PassThrough();
const offsetStream = this.offsetStream =
new stream_1.PassThrough({ transform: this.onChunk.bind(this) });
const delayStream = new stream_1.PassThrough();
const requestStream = yield this.getRequestStream(reqOpts);
this.setPipeline(bufferStream, offsetStream, requestStream, delayStream);

@@ -165,2 +180,6 @@ // wait for "complete" from request before letting the stream finish

const numBytesWritten = this.numBytesWritten;
this.emit('progress', {
bytesWritten: this.numBytesWritten,
contentLength: this.contentLength
});
// check if this is the same content uploaded previously. this caches a

@@ -196,12 +215,24 @@ // slice of the first chunk, then compares it with the first byte of

// only push data from the byte after the one we left off on
next(null, this.numBytesWritten > offset ? chunk : undefined);
next(undefined, this.numBytesWritten > offset ? chunk : undefined);
}
getAndSetOffset(callback) {
const opts = {
method: 'PUT',
url: this.uri,
headers: { 'Content-Length': 0, 'Content-Range': 'bytes */*' }
};
this.makeRequest(opts, (err, resp) => {
if (err) {
getAndSetOffset() {
return __awaiter(this, void 0, void 0, function* () {
const opts = {
method: 'PUT',
url: this.uri,
headers: { 'Content-Length': 0, 'Content-Range': 'bytes */*' }
};
try {
const resp = yield this.makeRequest(opts);
if (resp.status === RESUMABLE_INCOMPLETE_STATUS_CODE) {
if (resp.headers.range) {
const range = resp.headers.range;
this.offset = Number(range.split('-')[1]) + 1;
return;
}
}
this.offset = 0;
}
catch (err) {
const resp = err.response;
// we don't return a 404 to the user if they provided the resumable

@@ -212,3 +243,4 @@ // URI. if we're just using the configstore file to tell us that this

if (resp && resp.status === 404 && !this.uriProvidedManually) {
return this.restart();
this.restart();
return;
}

@@ -221,63 +253,64 @@ // this resumable upload is unrecoverable (bad data or service error).

if (resp && resp.status === TERMINATED_UPLOAD_STATUS_CODE) {
return this.restart();
}
return this.destroy(err);
}
if (resp && resp.status === RESUMABLE_INCOMPLETE_STATUS_CODE) {
if (resp.headers.range) {
const range = resp.headers.range;
this.offset = Number(range.split('-')[1]) + 1;
callback();
this.restart();
return;
}
this.destroy(err);
}
this.offset = 0;
callback();
});
}
makeRequest(reqOpts, callback) {
if (this.encryption) {
reqOpts.headers = reqOpts.headers || {};
reqOpts.headers['x-goog-encryption-algorithm'] = 'AES256';
reqOpts.headers['x-goog-encryption-key'] = this.encryption.key;
reqOpts.headers['x-goog-encryption-key-sha256'] = this.encryption.hash;
}
if (this.userProject) {
reqOpts.params = reqOpts.params || {};
reqOpts.params.userProject = this.userProject;
}
reqOpts.validateStatus = (status) => {
return (status >= 200 && status < 300) ||
status === RESUMABLE_INCOMPLETE_STATUS_CODE;
};
this.authClient.request(reqOpts).then(r => {
return callback(null, r, r.data);
}, (err) => {
const body = err.response ? err.response.data : undefined;
const e = (body && body.error) ? body.error : err;
return callback(e, err.response, body);
makeRequest(reqOpts) {
return __awaiter(this, void 0, void 0, function* () {
if (this.encryption) {
reqOpts.headers = reqOpts.headers || {};
reqOpts.headers['x-goog-encryption-algorithm'] = 'AES256';
reqOpts.headers['x-goog-encryption-key'] = this.encryption.key.toString();
reqOpts.headers['x-goog-encryption-key-sha256'] =
this.encryption.hash.toString();
}
if (this.userProject) {
reqOpts.params = reqOpts.params || {};
reqOpts.params.userProject = this.userProject;
}
reqOpts.validateStatus = () => true;
const res = yield this.authClient.request(reqOpts);
if (res.data && res.data.error) {
const err = new Error(res.data.error);
err.response = res;
throw err;
}
// If no error was returned, but the response had an invalid status
// code, create a new error to be passed to the callback.
if ((res.status < 200 || res.status >= 300) &&
res.status !== RESUMABLE_INCOMPLETE_STATUS_CODE) {
const e = new Error(`The request failed with a ${res.status}.`);
e.code = res.status;
}
return res;
});
}
getRequestStream(reqOpts, callback) {
if (this.userProject) {
reqOpts.params = reqOpts.params || {};
reqOpts.params.userProject = this.userProject;
}
this.authClient.authorizeRequest(reqOpts)
.then(opts => {
const authorizedReqOpts = axiosToRequest(reqOpts);
const requestStream = request(authorizedReqOpts);
requestStream.on('error', this.destroy.bind(this));
requestStream.on('response', this.onResponse.bind(this));
requestStream.on('complete', (resp) => {
const body = resp.body;
if (body && body.error)
this.destroy(body.error);
});
// this makes the response body come back in the response (weird?)
requestStream.callback = () => { };
callback(requestStream);
})
.catch(err => {
return this.destroy(wrapError('Could not authenticate request', err));
getRequestStream(reqOpts) {
return __awaiter(this, void 0, void 0, function* () {
try {
if (this.userProject) {
reqOpts.qs = reqOpts.qs || {};
reqOpts.qs.userProject = this.userProject;
}
const authHeaders = yield this.authClient.getRequestHeaders(reqOpts.url);
reqOpts.headers = Object.assign({}, reqOpts.headers, authHeaders);
const requestStream = request(reqOpts);
requestStream.on('error', this.destroy.bind(this));
requestStream.on('response', this.onResponse.bind(this));
requestStream.on('complete', (resp) => {
const body = resp.body;
if (body && body.error)
this.destroy(body.error);
});
// this makes the response body come back in the response (weird?)
requestStream.callback = () => { };
return requestStream;
}
catch (e) {
this.destroy(e);
throw e;
}
});

@@ -310,3 +343,3 @@ }

onResponse(resp) {
if (resp.status === 404) {
if (resp.statusCode === 404) {
if (this.numRetries < RETRY_LIMIT) {

@@ -321,3 +354,3 @@ this.numRetries++;

}
if (resp.status > 499 && resp.status < 600) {
if (resp.statusCode > 499 && resp.statusCode < 600) {
if (this.numRetries < RETRY_LIMIT) {

@@ -339,9 +372,2 @@ const randomMs = Math.round(Math.random() * 1000);

exports.Upload = Upload;
function axiosToRequest(opts) {
const reqOpts = opts;
reqOpts.qs = opts.params;
reqOpts.json = opts.data;
reqOpts.uri = opts.url;
return reqOpts;
}
function upload(cfg) {

@@ -353,5 +379,8 @@ return new Upload(cfg);

const up = new Upload(cfg);
up.createURI(callback);
if (!callback) {
return up.createURI();
}
up.createURI().then(r => callback(null, r), callback);
}
exports.createURI = createURI;
//# sourceMappingURL=index.js.map

@@ -7,2 +7,59 @@ # Changelog

## v0.14.0
01-23-2019 17:57 PST
### New Features
- feat: support async functions ([#164](https://github.com/googleapis/gcs-resumable-upload/pull/164))
- fix: use the reject handler for promises ([#144](https://github.com/googleapis/gcs-resumable-upload/pull/144))
- feat: add progress events ([#135](https://github.com/googleapis/gcs-resumable-upload/pull/135))
### Dependencies
- fix(deps): update dependency google-auth-library to v3 ([#165](https://github.com/googleapis/gcs-resumable-upload/pull/165))
- refactor: use teeny-request (part 1) ([#141](https://github.com/googleapis/gcs-resumable-upload/pull/141))
- chore(deps): update dependency @types/configstore to v4 ([#145](https://github.com/googleapis/gcs-resumable-upload/pull/145))
- chore(deps): update dependency typescript to ~3.2.0 ([#140](https://github.com/googleapis/gcs-resumable-upload/pull/140))
- chore(deps): update dependency gts to ^0.9.0 ([#137](https://github.com/googleapis/gcs-resumable-upload/pull/137))
- chore(deps): update dependency through2 to v3 ([#131](https://github.com/googleapis/gcs-resumable-upload/pull/131))
- refactor: move from axios back to request ([#123](https://github.com/googleapis/gcs-resumable-upload/pull/123))
- chore(deps): update dependency nock to v10 ([#113](https://github.com/googleapis/gcs-resumable-upload/pull/113))
- chore: update the version of typescript ([#106](https://github.com/googleapis/gcs-resumable-upload/pull/106))
### Documentation
- build: ignore googleapis.com in doc link checker ([#166](https://github.com/googleapis/gcs-resumable-upload/pull/166))
- build: check broken links in generated docs ([#162](https://github.com/googleapis/gcs-resumable-upload/pull/162))
### Internal / Testing Changes
- fix: fix the unit tests ([#161](https://github.com/googleapis/gcs-resumable-upload/pull/161))
- chore(build): inject yoshi automation key ([#160](https://github.com/googleapis/gcs-resumable-upload/pull/160))
- chore: update nyc and eslint configs ([#159](https://github.com/googleapis/gcs-resumable-upload/pull/159))
- chore: fix publish.sh permission +x ([#156](https://github.com/googleapis/gcs-resumable-upload/pull/156))
- fix(build): fix Kokoro release script ([#155](https://github.com/googleapis/gcs-resumable-upload/pull/155))
- build: add Kokoro configs for autorelease ([#154](https://github.com/googleapis/gcs-resumable-upload/pull/154))
- chore: always nyc report before calling codecov ([#153](https://github.com/googleapis/gcs-resumable-upload/pull/153))
- chore: nyc ignore build/test by default ([#152](https://github.com/googleapis/gcs-resumable-upload/pull/152))
- chore: update synth and common config ([#150](https://github.com/googleapis/gcs-resumable-upload/pull/150))
- fix(build): fix system key decryption ([#142](https://github.com/googleapis/gcs-resumable-upload/pull/142))
- chore: add synth.metadata
- chore: update eslintignore config ([#136](https://github.com/googleapis/gcs-resumable-upload/pull/136))
- chore: use latest npm on Windows ([#134](https://github.com/googleapis/gcs-resumable-upload/pull/134))
- chore: update CircleCI config ([#129](https://github.com/googleapis/gcs-resumable-upload/pull/129))
- chore: include build in eslintignore ([#126](https://github.com/googleapis/gcs-resumable-upload/pull/126))
- chore: update issue templates ([#121](https://github.com/googleapis/gcs-resumable-upload/pull/121))
- chore: remove old issue template ([#119](https://github.com/googleapis/gcs-resumable-upload/pull/119))
- build: run tests on node11 ([#118](https://github.com/googleapis/gcs-resumable-upload/pull/118))
- chores(build): run codecov on continuous builds ([#112](https://github.com/googleapis/gcs-resumable-upload/pull/112))
- chores(build): do not collect sponge.xml from windows builds ([#114](https://github.com/googleapis/gcs-resumable-upload/pull/114))
- chore: update new issue template ([#111](https://github.com/googleapis/gcs-resumable-upload/pull/111))
- build: fix codecov uploading on Kokoro ([#108](https://github.com/googleapis/gcs-resumable-upload/pull/108))
- Update kokoro config ([#105](https://github.com/googleapis/gcs-resumable-upload/pull/105))
- Update CI config ([#103](https://github.com/googleapis/gcs-resumable-upload/pull/103))
- Update kokoro config ([#101](https://github.com/googleapis/gcs-resumable-upload/pull/101))
- test: remove appveyor config ([#100](https://github.com/googleapis/gcs-resumable-upload/pull/100))
- Update kokoro config ([#99](https://github.com/googleapis/gcs-resumable-upload/pull/99))
- Enable prefer-const in the eslint config ([#98](https://github.com/googleapis/gcs-resumable-upload/pull/98))
- Enable no-var in eslint ([#97](https://github.com/googleapis/gcs-resumable-upload/pull/97))
- Update to new repo location ([#96](https://github.com/googleapis/gcs-resumable-upload/pull/96))
- Update CI config ([#95](https://github.com/googleapis/gcs-resumable-upload/pull/95))
## v0.13.0

@@ -9,0 +66,0 @@

{
"name": "gcs-resumable-upload",
"version": "0.13.0",
"version": "0.14.0",
"description": "Upload a file to Google Cloud Storage with built-in resumable behavior",
"repository": "GoogleCloudPlatform/gcs-resumable-upload",
"repository": "googleapis/gcs-resumable-upload",
"main": "build/src/index.js",

@@ -12,4 +12,3 @@ "types": "build/src/index.d.ts",

"scripts": {
"test": "npm run test-only",
"test-only": "mocha build/test",
"test": "nyc mocha build/test",
"lint": "gts check",

@@ -25,3 +24,3 @@ "clean": "gts clean",

"presystem-test": "npm run compile",
"docs": "jsdoc -c .jsdoc.js"
"docs": "compodoc src/"
},

@@ -45,5 +44,4 @@ "keywords": [

"dependencies": {
"axios": "^0.18.0",
"configstore": "^4.0.0",
"google-auth-library": "^2.0.0",
"google-auth-library": "^3.0.0",
"pumpify": "^1.5.1",

@@ -54,3 +52,4 @@ "request": "^2.87.0",

"devDependencies": {
"@types/configstore": "^2.1.1",
"@compodoc/compodoc": "^1.1.7",
"@types/configstore": "^4.0.0",
"@types/is-stream": "^1.1.0",

@@ -64,16 +63,16 @@ "@types/mocha": "^5.2.1",

"@types/through2": "^2.0.33",
"assert-rejects": "^1.0.0",
"gaxios": "^1.2.2",
"codecov": "^3.0.4",
"gts": "^0.8.0",
"ink-docstrap": "^1.3.2",
"gts": "^0.9.0",
"intelli-espower-loader": "^1.0.1",
"is-stream": "^1.1.0",
"jsdoc": "^3.5.5",
"mocha": "^5.2.0",
"mockery": "^2.1.0",
"nock": "^9.3.0",
"nock": "^10.0.0",
"nyc": "^13.0.0",
"source-map-support": "^0.5.6",
"through2": "^2.0.3",
"typescript": "~3.0.0"
"through2": "^3.0.0",
"typescript": "~3.2.0"
}
}

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