@elastic.io/object-storage-client
Advanced tools
Comparing version 1.0.0 to 1.0.1
/// <reference types="node" /> | ||
import { Readable, Duplex } from 'stream'; | ||
import { JWTPayload, ObjectOptions } from './storage-client'; | ||
import { AxiosResponse } from 'axios'; | ||
export interface ObjectDTO { | ||
@@ -8,2 +9,6 @@ stream?: Readable; | ||
} | ||
export interface ObjectDTOStringResponse { | ||
data: string; | ||
headers: any; | ||
} | ||
export declare type TransformMiddleware = () => Duplex; | ||
@@ -20,2 +25,3 @@ export default class ObjectStorage { | ||
getAsJSON(objectId: string, jwtPayloadOrToken?: JWTPayload | string): Promise<any>; | ||
getAsString(objectId: string, jwtPayloadOrToken?: JWTPayload | string): Promise<ObjectDTOStringResponse>; | ||
getAsStream(objectId: string, jwtPayloadOrToken?: JWTPayload | string): Promise<ObjectDTO>; | ||
@@ -26,2 +32,4 @@ deleteOne(objectId: string, jwtPayloadOrToken?: JWTPayload | string): Promise<void>; | ||
addAsJSON(data: any, jwtPayloadOrToken: JWTPayload | string, options?: ObjectOptions): Promise<string>; | ||
putAsStream(objectId: string, stream: () => Readable, jwtPayloadOrToken?: JWTPayload | string, options?: ObjectOptions): Promise<AxiosResponse>; | ||
putAsJSON(objectId: string, data: any, jwtPayloadOrToken?: JWTPayload | string, options?: ObjectOptions): Promise<AxiosResponse>; | ||
} |
@@ -27,2 +27,9 @@ "use strict"; | ||
} | ||
async getAsString(objectId, jwtPayloadOrToken) { | ||
const objectDTO = await this.getAsStream(objectId, jwtPayloadOrToken); | ||
return { | ||
data: await get_stream_1.default(objectDTO.stream), | ||
headers: objectDTO.headers | ||
}; | ||
} | ||
async getAsStream(objectId, jwtPayloadOrToken) { | ||
@@ -59,3 +66,20 @@ const res = await this.client.readStream(objectId, jwtPayloadOrToken); | ||
} | ||
async putAsStream(objectId, stream, jwtPayloadOrToken, options) { | ||
const resultStream = () => { | ||
return this.applyMiddlewares(stream(), this.forwards); | ||
}; | ||
return this.client.putOne(objectId, resultStream, jwtPayloadOrToken, options); | ||
} | ||
// eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
async putAsJSON(objectId, data, jwtPayloadOrToken, options) { | ||
const dataStream = () => { | ||
const dataString = JSON.stringify(data); | ||
const stream = new stream_1.Readable(); | ||
stream.push(dataString); | ||
stream.push(null); | ||
return stream; | ||
}; | ||
return this.putAsStream(objectId, dataStream, jwtPayloadOrToken, options); | ||
} | ||
} | ||
exports.default = ObjectStorage; |
@@ -9,2 +9,3 @@ /// <reference types="node" /> | ||
ttl: number; | ||
contentType: string; | ||
} | ||
@@ -30,2 +31,3 @@ export interface RequestOptions { | ||
deleteOne(objectId: string, jwtPayloadOrToken?: JWTPayload | string): Promise<AxiosResponse>; | ||
putOne(objectId: string, stream: () => Readable, jwtPayloadOrToken?: JWTPayload | string, options?: ObjectOptions): Promise<AxiosResponse>; | ||
} |
@@ -87,2 +87,12 @@ "use strict"; | ||
} | ||
async putOne(objectId, stream, jwtPayloadOrToken, options) { | ||
const headers = { | ||
'content-type': options && options.contentType ? options.contentType : 'application/octet-stream' | ||
}; | ||
if (options && options.ttl) { | ||
headers[ObjectHeaders.ttl] = options.ttl; | ||
} | ||
const res = await this.requestRetry(async () => this.api.put(`/objects/${objectId}`, stream(), { headers: await this.getHeaders(jwtPayloadOrToken, headers) })); | ||
return res; | ||
} | ||
} | ||
@@ -89,0 +99,0 @@ StorageClient.httpAgent = new http_1.default.Agent({ keepAlive: true }); |
{ | ||
"name": "@elastic.io/object-storage-client", | ||
"version": "1.0.0", | ||
"version": "1.0.1", | ||
"description": "Elastic.io Message Store Client", | ||
@@ -8,5 +8,6 @@ "main": "dist/index.js", | ||
"lint": "eslint --ext .ts .", | ||
"license-check": "license-checker --excludePrivatePackages --excludePackages \"$(node ../../../.ignored-licenses.js)\" --onlyAllow \"$(node ../../../.allowed-licenses.js)\"", | ||
"test": "NODE_ENV=test mocha -r ts-node/register --recursive ./spec/**/*.ts", | ||
"build": "tsc", | ||
"prepare" : "npm run build", | ||
"prepare": "npm run build", | ||
"prepublishOnly": "npm run lint && npm run test" | ||
@@ -17,3 +18,3 @@ }, | ||
"@elastic.io/bunyan-logger": "1.0.5", | ||
"axios": "0.21.1", | ||
"axios": "0.26.0", | ||
"get-stream": "5.1.0", | ||
@@ -25,3 +26,2 @@ "jsonwebtoken": "8.5.1", | ||
"devDependencies": { | ||
"@types/axios": "0.14.0", | ||
"@types/chai": "4.1.7", | ||
@@ -43,3 +43,5 @@ "@types/jsonwebtoken": "8.3.2", | ||
"eslint-plugin-promise": "4.0.1", | ||
"eslint-plugin-security": "1.4.0", | ||
"eslint-plugin-standard": "4.0.0", | ||
"license-checker": "25.0.1", | ||
"mocha": "6.1.4", | ||
@@ -46,0 +48,0 @@ "nock": "10.0.6", |
@@ -104,2 +104,21 @@ import nock from 'nock'; | ||
it('should retry get as string request 3 times on errors', async () => { | ||
const objectStorage = new ObjectStorage(config); | ||
const objectStorageCalls = nock(config.uri) | ||
// @ts-ignore: Nock .d.ts are outdated. | ||
.matchHeader('authorization', authHeaderMatch()) | ||
.get('/objects/1') | ||
.reply(500) | ||
.get('/objects/1') | ||
.replyWithError({ code: 'ECONNRESET' }) | ||
.get('/objects/1') | ||
.reply(200, streamResponse(responseData)); | ||
const { data } = await objectStorage.getAsString('1', {}); | ||
expect(objectStorageCalls.isDone()).to.be.true; | ||
expect(data).to.be.deep.equal(JSON.stringify(responseData)); | ||
}); | ||
it('should retry post request 3 times on errors', async () => { | ||
@@ -123,2 +142,21 @@ const objectStorage = new ObjectStorage(config); | ||
it('should retry put request 3 times on errors', async () => { | ||
const objectStorage = new ObjectStorage(config); | ||
const objectStorageCalls = nock(config.uri) | ||
// @ts-ignore: Nock .d.ts are outdated. | ||
.matchHeader('authorization', authHeaderMatch()) | ||
.put('/objects/1') | ||
.replyWithError({ code: 'ECONNREFUSED' }) | ||
.put('/objects/1') | ||
.reply(400) | ||
.put('/objects/1') | ||
.reply(200, responseData); | ||
const response = await objectStorage.putAsJSON('1', postData, {}); | ||
expect(response.data).to.deep.equal(responseData); | ||
expect(objectStorageCalls.isDone()).to.be.true; | ||
}); | ||
it('should accept jwt token on add', async () => { | ||
@@ -171,2 +209,18 @@ const objectStorage = new ObjectStorage({ uri: config.uri }); | ||
it('should accept jwt token on put', async () => { | ||
const objectStorage = new ObjectStorage({ uri: config.uri }); | ||
const jwtPayload = { tenantId: '12', contractId: '1' }; | ||
const objectStorageCalls = nock(config.uri) | ||
// @ts-ignore: Nock .d.ts are outdated. | ||
.matchHeader('authorization', authHeaderMatch(jwtPayload)) | ||
.put('/objects/1') | ||
.reply(200, responseData); | ||
const response = await objectStorage.putAsJSON('1', postData, sign(jwtPayload, config.jwtSecret)); | ||
expect(response.data).to.deep.equal(responseData); | ||
expect(objectStorageCalls.isDone()).to.be.true; | ||
}); | ||
it('should throw exception if neither jwt secret, nor jwt token provided', async () => { | ||
@@ -280,2 +334,21 @@ const objectStorage = new ObjectStorage({ uri: config.uri }); | ||
it('should retry put request 3 times on errors', async () => { | ||
const objectStorage = new ObjectStorage(config); | ||
const objectStorageCalls = nock(config.uri) | ||
// @ts-ignore: Nock .d.ts are outdated. | ||
.matchHeader('authorization', authHeaderMatch()) | ||
.put('/objects/1') | ||
.replyWithError({ code: 'ECONNREFUSED' }) | ||
.put('/objects/1') | ||
.reply(400) | ||
.put('/objects/1') | ||
.reply(200, responseData); | ||
const response = await objectStorage.putAsStream('1', postStream, {}); | ||
expect(response.data).to.deep.equal(responseData); | ||
expect(objectStorageCalls.isDone()).to.be.true; | ||
}); | ||
it('should put successfully', async () => { | ||
@@ -311,2 +384,18 @@ const objectStorage = new ObjectStorage(config); | ||
}); | ||
it('should accept jwt token on put', async () => { | ||
const objectStorage = new ObjectStorage(config); | ||
const jwtPayload = { tenantId: '12', contractId: '1' }; | ||
const objectStorageCalls = nock(config.uri) | ||
// @ts-ignore: Nock .d.ts are outdated. | ||
.matchHeader('authorization', authHeaderMatch(jwtPayload)) | ||
.put('/objects/1') | ||
.reply(200, responseData); | ||
const response = await objectStorage.putAsStream('1', postStream, jwtPayload); | ||
expect(response.data).to.deep.equal(responseData); | ||
expect(objectStorageCalls.isDone()).to.be.true; | ||
}); | ||
}); | ||
@@ -387,2 +476,22 @@ }); | ||
it('should retry put request 3 times on errors', async () => { | ||
const objectStorageWithMiddlewares = new ObjectStorage(config); | ||
objectStorageWithMiddlewares.use(encryptStream, decryptStream); | ||
objectStorageWithMiddlewares.use(zip, unzip); | ||
const objectStorageWithMiddlewaresCalls = nock(config.uri) | ||
// @ts-ignore: Nock .d.ts are outdated. | ||
.matchHeader('authorization', authHeaderMatch()) | ||
.put('/objects/1') | ||
.replyWithError({ code: 'ECONNREFUSED' }) | ||
.put('/objects/1') | ||
.reply(400) | ||
.put('/objects/1') | ||
.reply(200, responseData); | ||
const response = await objectStorageWithMiddlewares.putAsJSON('1', postData, {}); | ||
expect(response.data).to.deep.equal(responseData); | ||
expect(objectStorageWithMiddlewaresCalls.isDone()).to.be.true; | ||
}); | ||
it('should accept jwt token on add', async () => { | ||
@@ -405,2 +514,19 @@ const objectStorageWithMiddlewares = new ObjectStorage(config); | ||
it('should accept jwt token on put', async () => { | ||
const objectStorageWithMiddlewares = new ObjectStorage(config); | ||
objectStorageWithMiddlewares.use(encryptStream, decryptStream); | ||
objectStorageWithMiddlewares.use(zip, unzip); | ||
const jwtPayload = { tenantId: '12', contractId: '1' }; | ||
const objectStorageWithMiddlewaresCalls = nock(config.uri) | ||
// @ts-ignore: Nock .d.ts are outdated. | ||
.matchHeader('authorization', authHeaderMatch(jwtPayload)) | ||
.put('/objects/1') | ||
.reply(200, responseData); | ||
const response = await objectStorageWithMiddlewares.putAsJSON('1', postData, sign(jwtPayload, config.jwtSecret)); | ||
expect(response.data).to.deep.equal(responseData); | ||
expect(objectStorageWithMiddlewaresCalls.isDone()).to.be.true; | ||
}); | ||
it('should accept jwt token on get', async () => { | ||
@@ -447,2 +573,23 @@ const objectStorageWithMiddlewares = new ObjectStorage(config); | ||
it('should put 2 objects successfully', async () => { | ||
const objectStorageWithMiddlewares = new ObjectStorage(config); | ||
objectStorageWithMiddlewares.use(encryptStream, decryptStream); | ||
objectStorageWithMiddlewares.use(zip, unzip); | ||
const jwtPayload = { tenantId: '12', contractId: '1' }; | ||
const objectStorageWithMiddlewaresCalls = nock(config.uri) | ||
// @ts-ignore: Nock .d.ts are outdated. | ||
.matchHeader('authorization', authHeaderMatch(jwtPayload)) | ||
.put('/objects/1') | ||
.reply(200, responseData) | ||
.put('/objects/2') | ||
.reply(200, responseData); | ||
const responseFirst = await objectStorageWithMiddlewares.putAsJSON('1', postData, sign(jwtPayload, config.jwtSecret)); | ||
const responseSecond = await objectStorageWithMiddlewares.putAsJSON('2', postData, sign(jwtPayload, config.jwtSecret)); | ||
expect(objectStorageWithMiddlewaresCalls.isDone()).to.be.true; | ||
expect(responseFirst.data).to.deep.equal(responseData); | ||
expect(responseSecond.data).to.deep.equal(responseData); | ||
}); | ||
it('should get 2 objects successfully', async () => { | ||
@@ -590,2 +737,22 @@ const objectStorageWithMiddlewares = new ObjectStorage(config); | ||
it('should retry put request 3 times on errors', async () => { | ||
const objectStorageWithMiddlewares = new ObjectStorage(config); | ||
objectStorageWithMiddlewares.use(encryptStream, decryptStream); | ||
objectStorageWithMiddlewares.use(zip, unzip); | ||
const objectStorageWithMiddlewaresCalls = nock(config.uri) | ||
// @ts-ignore: Nock .d.ts are outdated. | ||
.matchHeader('authorization', authHeaderMatch()) | ||
.put('/objects/1') | ||
.replyWithError({ code: 'ECONNREFUSED' }) | ||
.put('/objects/1') | ||
.reply(400) | ||
.put('/objects/1') | ||
.reply(200, responseData); | ||
const response = await objectStorageWithMiddlewares.putAsStream('1', postStream, {}); | ||
expect(response.data).to.deep.equal(responseData); | ||
expect(objectStorageWithMiddlewaresCalls.isDone()).to.be.true; | ||
}); | ||
it('should post successfully', async () => { | ||
@@ -627,2 +794,23 @@ const objectStorageWithMiddlewares = new ObjectStorage(config); | ||
it('should put 2 objects successfully', async () => { | ||
const objectStorageWithMiddlewares = new ObjectStorage(config); | ||
objectStorageWithMiddlewares.use(encryptStream, decryptStream); | ||
objectStorageWithMiddlewares.use(zip, unzip); | ||
const jwtPayload = { tenantId: '12', contractId: '1' }; | ||
const objectStorageWithMiddlewaresCalls = nock(config.uri) | ||
// @ts-ignore: Nock .d.ts are outdated. | ||
.matchHeader('authorization', authHeaderMatch(jwtPayload)) | ||
.put('/objects/1') | ||
.reply(200, responseData) | ||
.put('/objects/2') | ||
.reply(200, responseData); | ||
const responseFirst = await objectStorageWithMiddlewares.putAsStream('1', postStream, sign(jwtPayload, config.jwtSecret)); | ||
const responseSecond = await objectStorageWithMiddlewares.putAsStream('2', postStream, sign(jwtPayload, config.jwtSecret)); | ||
expect(objectStorageWithMiddlewaresCalls.isDone()).to.be.true; | ||
expect(responseFirst.data).to.deep.equal(responseData); | ||
expect(responseSecond.data).to.deep.equal(responseData); | ||
}); | ||
it('should get 2 objects successfully', async () => { | ||
@@ -629,0 +817,0 @@ const objectStorageWithMiddlewares = new ObjectStorage(config); |
@@ -166,2 +166,75 @@ import nock from 'nock'; | ||
}); | ||
describe('#putOne', () => { | ||
it('should fail after 3 retries', async () => { | ||
const storageClient = new StorageClient(config); | ||
const storageClientCalls = nock(config.uri) | ||
// @ts-ignore: Nock .d.ts are outdated. | ||
.matchHeader('authorization', authHeaderMatch()) | ||
.put('/objects/1') | ||
.replyWithError({ code: 'ECONNREFUSED' }) | ||
.put('/objects/1') | ||
.reply(400) | ||
.put('/objects/1') | ||
.replyWithError({ code: 'ENOTFOUND' }); | ||
let err; | ||
try { | ||
await storageClient.putOne('1', putStream, {}); | ||
} catch (e) { | ||
err = e; | ||
} | ||
expect(err.code).to.be.equal('ENOTFOUND'); | ||
expect(storageClientCalls.isDone()).to.be.true; | ||
}); | ||
it('should retry post request 3 times on errors', async () => { | ||
const storageClient = new StorageClient(config); | ||
const storageClientCalls = nock(config.uri) | ||
// @ts-ignore: Nock .d.ts are outdated. | ||
.matchHeader('authorization', authHeaderMatch()) | ||
.put('/objects/1') | ||
.replyWithError({ code: 'ECONNREFUSED' }) | ||
.put('/objects/1') | ||
.reply(400) | ||
.put('/objects/1') | ||
.reply(200, responseData); | ||
const response = await storageClient.putOne('1', putStream, {}); | ||
expect(response.data).to.be.deep.equal(responseData); | ||
expect(storageClientCalls.isDone()).to.be.true; | ||
}); | ||
it('should accept jwt token on add', async () => { | ||
const storageClient = new StorageClient({ uri: config.uri }); | ||
const jwtPayload = { tenantId: '12', contractId: '1' }; | ||
const storageClientCalls = nock(config.uri) | ||
// @ts-ignore: Nock .d.ts are outdated. | ||
.matchHeader('authorization', authHeaderMatch(jwtPayload)) | ||
.put('/objects/1') | ||
.reply(200, responseData); | ||
const response = await storageClient.putOne('1', putStream, sign(jwtPayload, config.jwtSecret)); | ||
expect(storageClientCalls.isDone()).to.be.true; | ||
expect(response.data).to.be.deep.equal(responseData); | ||
expect(storageClientCalls.isDone()).to.be.true; | ||
}); | ||
it('should throw exception if neither jwt secret, nor jwt token provided', async () => { | ||
const storageClient = new StorageClient({ uri: config.uri }); | ||
let err; | ||
try { | ||
await storageClient.putOne('1', putStream, {}); | ||
} catch (e) { | ||
err = e; | ||
} | ||
expect(err.toString()).to.include('JWT'); | ||
}); | ||
}); | ||
}); |
import { Readable, Duplex } from 'stream'; | ||
import getStream from 'get-stream'; | ||
import StorageClient, { JWTPayload, ObjectOptions } from './storage-client'; | ||
import { AxiosResponse } from 'axios'; | ||
@@ -11,2 +12,8 @@ export interface ObjectDTO { | ||
export interface ObjectDTOStringResponse { | ||
data: string; | ||
// eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
headers: any; | ||
} | ||
export type TransformMiddleware = () => Duplex; | ||
@@ -38,2 +45,10 @@ | ||
public async getAsString(objectId: string, jwtPayloadOrToken?: JWTPayload | string): Promise<ObjectDTOStringResponse> { | ||
const objectDTO = await this.getAsStream(objectId, jwtPayloadOrToken); | ||
return { | ||
data: await getStream(objectDTO.stream), | ||
headers: objectDTO.headers | ||
}; | ||
} | ||
public async getAsStream(objectId: string, jwtPayloadOrToken?: JWTPayload | string): Promise<ObjectDTO> { | ||
@@ -74,2 +89,21 @@ const res = await this.client.readStream(objectId, jwtPayloadOrToken); | ||
} | ||
public async putAsStream(objectId: string, stream: () => Readable, jwtPayloadOrToken?: JWTPayload | string, options?: ObjectOptions): Promise<AxiosResponse> { | ||
const resultStream = () => { | ||
return this.applyMiddlewares(stream(), this.forwards); | ||
}; | ||
return this.client.putOne(objectId, resultStream, jwtPayloadOrToken, options); | ||
} | ||
// eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
public async putAsJSON(objectId: string, data: any, jwtPayloadOrToken?: JWTPayload | string, options?: ObjectOptions): Promise<AxiosResponse> { | ||
const dataStream = () => { | ||
const dataString = JSON.stringify(data); | ||
const stream = new Readable(); | ||
stream.push(dataString); | ||
stream.push(null); | ||
return stream; | ||
}; | ||
return this.putAsStream(objectId, dataStream, jwtPayloadOrToken, options); | ||
} | ||
} |
@@ -18,2 +18,3 @@ import axios, { AxiosInstance, AxiosResponse } from 'axios'; | ||
ttl: number; | ||
contentType: string; | ||
}; | ||
@@ -112,2 +113,15 @@ | ||
} | ||
public async putOne(objectId: string, stream: () => Readable, jwtPayloadOrToken?: JWTPayload | string, options?: ObjectOptions): Promise<AxiosResponse> { | ||
const headers: RequestHeaders = { | ||
'content-type': options && options.contentType ? options.contentType : 'application/octet-stream' | ||
}; | ||
if (options && options.ttl) { | ||
headers[ObjectHeaders.ttl] = options.ttl; | ||
} | ||
const res = await this.requestRetry( | ||
async (): Promise<AxiosResponse> => this.api.put(`/objects/${objectId}`, stream(), { headers: await this.getHeaders(jwtPayloadOrToken, headers) }) | ||
); | ||
return res; | ||
} | ||
} |
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
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
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
73215
1463
24
3
+ Addedaxios@0.26.0(transitive)
- Removedaxios@0.21.1(transitive)
Updatedaxios@0.26.0