kinvey-flex-sdk
Advanced tools
Comparing version 3.2.1 to 3.3.0-alpha.1
## Changelog | ||
### 3.3.0 | ||
* Added new onInsertMulti data event for handling insertion of Arrays | ||
* Added support for arrays in dataStore.save() | ||
### 3.2.1 | ||
* When making requests to Kinvey, use original requests computed API version rather than relying on the header API Version. | ||
@@ -5,0 +9,0 @@ * Change default API version to 3 when making requests to Kinvey and no API version is present |
@@ -31,2 +31,9 @@ /** | ||
function getPublicConnectionErrorMsg(receiverMsg) { | ||
if (receiverMsg === 'Connection ended by client.') { | ||
return 'Flex Service request timed out.'; | ||
} | ||
return 'Unexpected network issue.'; | ||
} | ||
class Flex { | ||
@@ -88,2 +95,9 @@ constructor(opt, cb) { | ||
const complete = (task) => { | ||
const errorMsg = completionCallback(null, task); | ||
if (errorMsg && options.type === 'tcp') { | ||
this.logger.error(`Unable to send response for taskId ${task.taskId}: ${getPublicConnectionErrorMsg(errorMsg)}`); | ||
} | ||
}; | ||
if (this.sharedSecret != null | ||
@@ -103,3 +117,3 @@ && task.taskType !== 'serviceDiscovery' | ||
task.response.continue = false; | ||
return completionCallback(null, task); | ||
return complete(task); | ||
} | ||
@@ -118,3 +132,3 @@ | ||
task.response.continue = false; | ||
return completionCallback(null, task); | ||
return complete(task); | ||
} | ||
@@ -134,7 +148,7 @@ | ||
}; | ||
return completionCallback(null, task); | ||
return complete(task); | ||
} | ||
return this[task.taskType].process(task, this.moduleGenerator.generate(task), (taskWithError, task) => { | ||
completionCallback(null, taskWithError || task); | ||
complete(taskWithError || task); | ||
}); | ||
@@ -141,0 +155,0 @@ }); |
@@ -15,2 +15,3 @@ /** | ||
const logger = require('./logger'); | ||
const notImplementedHandler = require('./notImplementedHandler'); | ||
@@ -20,2 +21,6 @@ | ||
function logAlreadyResponded(handlerName) { | ||
logger.error(`Invoked done() or next() more than once to the same FlexAuth request in handler "${handlerName}"`); | ||
} | ||
function getHandlers() { | ||
@@ -46,4 +51,5 @@ return [...authFunctions.keys()]; | ||
function authCompletionHandler(task, callback) { | ||
let responseCallback = callback; | ||
function completionHandler(token) { | ||
const responseCallback = callback; | ||
const result = task.response; | ||
@@ -134,3 +140,4 @@ | ||
result.continue = false; | ||
return responseCallback(null, task); | ||
responseCallback(null, task); | ||
responseCallback = logAlreadyResponded.bind(null, task.taskName); | ||
}, | ||
@@ -145,3 +152,4 @@ done() { | ||
result.continue = false; | ||
return responseCallback(null, task); | ||
responseCallback(null, task); | ||
responseCallback = logAlreadyResponded.bind(null, task.taskName); | ||
} | ||
@@ -148,0 +156,0 @@ }; |
@@ -22,2 +22,3 @@ /** | ||
'onInsert', | ||
'onInsertMany', | ||
'onDeleteById', | ||
@@ -60,2 +61,6 @@ 'onDeleteAll', | ||
onInsertMany(functionToExecute) { | ||
this.register('onInsertMany', functionToExecute); | ||
} | ||
onDeleteById(functionToExecute) { | ||
@@ -163,3 +168,7 @@ this.register('onDeleteById', functionToExecute); | ||
if (task.method === 'POST') { | ||
dataOp = 'onInsert'; | ||
if (Array.isArray(task.request.body)) { | ||
dataOp = 'onInsertMany'; | ||
} else { | ||
dataOp = 'onInsert'; | ||
} | ||
} else if (task.method === 'PUT') { | ||
@@ -166,0 +175,0 @@ dataOp = 'onUpdate'; |
@@ -15,8 +15,24 @@ /** | ||
const logger = require('./logger'); | ||
function isFunctionHandler(taskType) { | ||
return taskType === 'businessLogic' || taskType === 'functions'; | ||
} | ||
function logAlreadyResponded(task) { | ||
let message = 'Invoked done() or next() more than once to the same Flex '; | ||
if (isFunctionHandler(task.taskType)) { | ||
message += `Functions request to "${task.taskName}"`; | ||
} else { | ||
message += `Data handler ${task.request.method} for ${task.request.serviceObjectName}`; | ||
} | ||
logger.error(message); | ||
} | ||
function createCompletionHandler(task, requestBody, cb) { | ||
const callback = !cb && typeof requestBody === 'function' ? requestBody : cb; | ||
const updateRequestBody = typeof requestBody === 'function' ? {} : requestBody; | ||
let responseCallback = callback; | ||
function completionHandler(body) { | ||
let responseCallback = callback; | ||
const result = {}; | ||
@@ -153,4 +169,3 @@ | ||
responseCallback(null, task); | ||
responseCallback = () => null; | ||
return responseCallback; | ||
responseCallback = logAlreadyResponded.bind(null, task); | ||
}, | ||
@@ -176,4 +191,3 @@ next() { | ||
responseCallback(null, task); | ||
responseCallback = () => null; | ||
return responseCallback; | ||
responseCallback = logAlreadyResponded.bind(null, task); | ||
} | ||
@@ -180,0 +194,0 @@ }; |
@@ -47,4 +47,3 @@ /** | ||
const requestOptions = this._buildAppdataRequest(collectionName); | ||
if (entity._id) { | ||
if (!Array.isArray(entity) && entity._id) { | ||
requestOptions.method = 'PUT'; | ||
@@ -51,0 +50,0 @@ requestOptions.url += entity._id; |
{ | ||
"name": "kinvey-flex-sdk", | ||
"version": "3.2.1", | ||
"version": "3.3.0-alpha.1", | ||
"description": "SDK for creating Kinvey Flex Services", | ||
@@ -20,3 +20,3 @@ "engines": { | ||
"bson": "0.4.23", | ||
"kinvey-code-task-runner": "2.3.1", | ||
"kinvey-code-task-runner": "2.4.0", | ||
"kinvey-datalink-errors": "0.3.2", | ||
@@ -35,3 +35,3 @@ "moment": "2.22.2", | ||
"should": "13.2.3", | ||
"sinon": "7.1.1", | ||
"sinon": "7.2.7", | ||
"test-console": "1.1.0", | ||
@@ -38,0 +38,0 @@ "uuid": "3.3.2" |
@@ -15,5 +15,9 @@ /** | ||
const auth = require('../../../lib/service/auth'); | ||
const should = require('should'); | ||
const sinon = require('sinon'); | ||
const proxyquire = require('proxyquire'); | ||
const loggerMock = require('./mocks/loggerMock'); | ||
const auth = proxyquire('../../../lib/service/auth', { './logger': loggerMock }); | ||
function quickRandom() { | ||
@@ -133,2 +137,3 @@ return Math.floor((Math.random() * (1000 - 1)) + 1); | ||
afterEach((done) => { | ||
loggerMock.error.resetHistory(); | ||
auth.clearAll(); | ||
@@ -188,3 +193,2 @@ return done(); | ||
}); | ||
it('should return a 401 server_error', (done) => { | ||
@@ -262,3 +266,33 @@ const taskName = quickRandom(); | ||
}); | ||
['next', 'done'].forEach((method1) => { | ||
['next', 'done'].forEach((method2) => { | ||
it(`should log a message when attempting to respond more than once, by calling ${method1}() and then ${method2}()`, (done) => { | ||
const taskName = quickRandom(); | ||
const task = sampleTask(taskName); | ||
auth.register(taskName, (context, complete) => { | ||
complete({ foo: 'bar' }).ok()[method1](); | ||
setTimeout(() => { | ||
complete({ foo: 'not bar' }).ok()[method2](); | ||
}, 0); | ||
}); | ||
const processCallbackSpy = sinon.spy((err, result) => { | ||
should.not.exist(err); | ||
result.response.statusCode.should.eql(200); | ||
result.response.body.should.eql({ token: { foo: 'bar' }, authenticated: true }); | ||
result.response.continue.should.eql(false); | ||
}); | ||
loggerMock.error = sinon.spy((message) => { | ||
message.should.eql(`Invoked done() or next() more than once to the same FlexAuth request in handler "${taskName}"`); | ||
processCallbackSpy.calledOnce.should.eql(true); | ||
done(); | ||
}); | ||
auth.process(task, null, processCallbackSpy); | ||
}); | ||
}); | ||
}); | ||
}); | ||
}); |
@@ -15,5 +15,10 @@ /** | ||
const data = require('../../../lib/service/data'); | ||
const should = require('should'); | ||
const sinon = require('sinon'); | ||
const proxyquire = require('proxyquire'); | ||
const loggerMock = require('./mocks/loggerMock'); | ||
const completionHandler = proxyquire('../../../lib/service/kinveyCompletionHandler', { './logger': loggerMock }); | ||
const data = proxyquire('../../../lib/service/data', { './kinveyCompletionHandler': completionHandler }); | ||
const serviceObjectName = 'myServiceObject'; | ||
@@ -42,2 +47,3 @@ | ||
afterEach((done) => { | ||
loggerMock.error.resetHistory(); | ||
data.clearAll(); | ||
@@ -52,2 +58,7 @@ return done(); | ||
}); | ||
it('can register insertMany ', (done) => { | ||
data.serviceObject(serviceObjectName).onInsertMany(() => done()); | ||
const fn = data.serviceObject(serviceObjectName).resolve('onInsertMany'); | ||
return fn(); | ||
}); | ||
it('can register a deleteAll', (done) => { | ||
@@ -195,2 +206,15 @@ data.serviceObject(serviceObjectName).onDeleteAll(() => done()); | ||
}); | ||
it('can explicitly set an array body', (done) => { | ||
const task = sampleTask(); | ||
task.request.body = []; | ||
data.serviceObject(serviceObjectName).onInsertMany((context, complete) => complete() | ||
.setBody([{ foo: 'bar' }]) | ||
.ok() | ||
.done()); | ||
return data.process(task, {}, (err, result) => { | ||
should.not.exist(err); | ||
result.response.body.should.eql([{ foo: 'bar' }]); | ||
done(); | ||
}); | ||
}); | ||
it('can process an insert', (done) => { | ||
@@ -214,2 +238,31 @@ const task = sampleTask(); | ||
}); | ||
it('can process insertMany with an empty array body', (done) => { | ||
const task = sampleTask(); | ||
task.request.body = []; | ||
data.serviceObject(serviceObjectName).onInsertMany((context) => { | ||
context.body.should.eql([]); | ||
return done(); | ||
}); | ||
return data.process(task, {}, () => {}); | ||
}); | ||
it('can process insertMany with an array body', (done) => { | ||
const task = sampleTask(); | ||
task.request.body = [{ foo: 'bar' }, { foo2: 'bar2' }]; | ||
data.serviceObject(serviceObjectName).onInsertMany((context) => { | ||
context.body.should.eql(task.request.body); | ||
return done(); | ||
}); | ||
return data.process(task, {}, () => {}); | ||
}); | ||
it('can process insertMany and include request, complete, and modules', (done) => { | ||
const task = sampleTask(); | ||
task.request.body = []; | ||
data.serviceObject(serviceObjectName).onInsertMany((context, complete, modules) => { | ||
context.should.be.an.Object(); | ||
complete.should.be.a.Function(); | ||
modules.should.be.an.Object(); | ||
return done(); | ||
}); | ||
return data.process(task, {}, () => {}); | ||
}); | ||
it('can process an update', (done) => { | ||
@@ -493,2 +546,5 @@ const task = sampleTask(); | ||
describe('completion handlers', () => { | ||
afterEach(() => { | ||
loggerMock.error.resetHistory(); | ||
}); | ||
it('should return a successful response', (done) => { | ||
@@ -660,3 +716,34 @@ const task = sampleTask(); | ||
}); | ||
['next', 'done'].forEach((method1) => { | ||
['next', 'done'].forEach((method2) => { | ||
it(`should log a message when attempting to respond more than once, by calling ${method1}() and then ${method2}()`, (done) => { | ||
const task = sampleTask(); | ||
data.serviceObject(serviceObjectName).onInsert((context, complete) => { | ||
complete({ foo: 'bar' }).ok()[method1](); | ||
setTimeout(() => { | ||
complete({ foo: 'not bar' }).ok()[method2](); | ||
}, 0); | ||
}); | ||
const processCallbackSpy = sinon.spy((err, result) => { | ||
should.not.exist(err); | ||
result.response.statusCode.should.eql(200); | ||
result.response.body.should.eql({ | ||
foo: 'bar' | ||
}); | ||
result.response.continue.should.eql(method1 === 'next'); | ||
}); | ||
loggerMock.error = sinon.spy((message) => { | ||
const { method, serviceObjectName } = task.request; | ||
message.should.eql(`Invoked done() or next() more than once to the same Flex Data handler ${method} for ${serviceObjectName}`); | ||
processCallbackSpy.calledOnce.should.eql(true); | ||
done(); | ||
}); | ||
data.process(task, {}, processCallbackSpy); | ||
}); | ||
}); | ||
}); | ||
}); | ||
}); |
@@ -26,7 +26,16 @@ /** | ||
let sdk = null; | ||
before((done) => { | ||
sdk = proxyquire('../../../lib/flex', { 'kinvey-code-task-runner': mockTaskReceiver }); | ||
return done(); | ||
before(() => { | ||
this.loggerMock = { error: sinon.spy() }; | ||
sdk = proxyquire('../../../lib/flex', { | ||
'kinvey-code-task-runner': mockTaskReceiver, | ||
'./service/logger': this.loggerMock | ||
}); | ||
}); | ||
it('can create a new service', done => | ||
beforeEach(() => { | ||
this.loggerMock.error = sinon.spy(); | ||
}); | ||
it('can create a new service', (done) => { | ||
sdk.service((err, flex) => { | ||
@@ -41,4 +50,5 @@ should.not.exist(err); | ||
flex.version.should.eql(flexPackageJson.version); | ||
return done(); | ||
})); | ||
done(); | ||
}); | ||
}); | ||
@@ -412,2 +422,94 @@ it('should set the type to http by default', (done) => { | ||
}); | ||
it('should log a timeout error, if receiver returns a client disconnect error', (done) => { | ||
process.env.SDK_RECEIVER = 'tcp'; | ||
sdk.service((err, sdk) => { | ||
const task = { | ||
taskId: `some id ${Math.random()}`, | ||
appMetadata: { | ||
_id: '12345', | ||
appsecret: 'appsecret', | ||
mastersecret: 'mastersecret', | ||
pushService: undefined, | ||
restrictions: { | ||
level: 'starter' | ||
}, | ||
API_version: 3, | ||
name: 'DevApp', | ||
platform: null | ||
}, | ||
taskType: 'functions', | ||
taskName: 'foo', | ||
hookType: 'customEndpoint', | ||
method: 'GET', | ||
request: { | ||
method: 'GET', | ||
headers: {}, | ||
body: {} | ||
}, | ||
response: { | ||
headers: {} | ||
} | ||
}; | ||
sdk.functions.register('foo', (context, complete) => { | ||
complete().ok().done(); | ||
}); | ||
mockTaskReceiver.taskReceived()(task, (err, result) => { | ||
return 'Connection ended by client.'; | ||
}); | ||
this.loggerMock.error.calledOnce.should.eql(true); | ||
this.loggerMock.error.firstCall.args.length.should.eql(1); | ||
this.loggerMock.error.firstCall.args[0].should.eql(`Unable to send response for taskId ${task.taskId}: Flex Service request timed out.`); | ||
done(); | ||
}); | ||
}); | ||
it('should log an unknown network error, if receiver returns an error which isn\'t a client disconnect', (done) => { | ||
process.env.SDK_RECEIVER = 'tcp'; | ||
sdk.service((err, sdk) => { | ||
const task = { | ||
taskId: `some id ${Math.random()}`, | ||
appMetadata: { | ||
_id: '12345', | ||
appsecret: 'appsecret', | ||
mastersecret: 'mastersecret', | ||
pushService: undefined, | ||
restrictions: { | ||
level: 'starter' | ||
}, | ||
API_version: 3, | ||
name: 'DevApp', | ||
platform: null | ||
}, | ||
taskType: 'functions', | ||
taskName: 'foo', | ||
hookType: 'customEndpoint', | ||
method: 'GET', | ||
request: { | ||
method: 'GET', | ||
headers: {}, | ||
body: {} | ||
}, | ||
response: { | ||
headers: {} | ||
} | ||
}; | ||
sdk.functions.register('foo', (context, complete) => { | ||
complete().ok().done(); | ||
}); | ||
mockTaskReceiver.taskReceived()(task, (err, result) => { | ||
return `Any other message ${Math.random()}`; | ||
}); | ||
this.loggerMock.error.calledOnce.should.eql(true); | ||
this.loggerMock.error.firstCall.args.length.should.eql(1); | ||
this.loggerMock.error.firstCall.args[0].should.eql(`Unable to send response for taskId ${task.taskId}: Unexpected network issue.`); | ||
done(); | ||
}); | ||
}); | ||
}); |
@@ -15,5 +15,10 @@ /** | ||
const functions = require('../../../lib/service/functions'); | ||
const should = require('should'); | ||
const sinon = require('sinon'); | ||
const proxyquire = require('proxyquire'); | ||
const loggerMock = require('./mocks/loggerMock'); | ||
const completionHandler = proxyquire('../../../lib/service/kinveyCompletionHandler', { './logger': loggerMock }); | ||
const functions = proxyquire('../../../lib/service/functions', { './kinveyCompletionHandler': completionHandler }); | ||
const testTaskName = 'myTaskName'; | ||
@@ -213,2 +218,3 @@ | ||
afterEach((done) => { | ||
loggerMock.error.resetHistory(); | ||
functions.clearAll(); | ||
@@ -673,3 +679,33 @@ return done(); | ||
}); | ||
['next', 'done'].forEach((method1) => { | ||
['next', 'done'].forEach((method2) => { | ||
it(`should log a message when attempting to respond more than once, by calling ${method1}() and then ${method2}()`, (done) => { | ||
const taskName = quickRandom(); | ||
const task = sampleTask(taskName); | ||
functions.register(taskName, (context, complete) => { | ||
complete({ baz: 'bar' }).ok()[method1](); | ||
setTimeout(() => { | ||
complete({ baz: 'not bar' }).ok()[method2](); | ||
}, 0); | ||
}); | ||
const processCallbackSpy = sinon.spy((err, result) => { | ||
should.not.exist(err); | ||
result.response.statusCode.should.eql(200); | ||
const expectedBody = method1 === 'next' ? result.request.body : result.response.body; | ||
expectedBody.should.eql({ baz: 'bar' }); | ||
result.response.continue.should.eql(method1 === 'next'); | ||
}); | ||
loggerMock.error = sinon.spy((message) => { | ||
message.should.eql(`Invoked done() or next() more than once to the same Flex Functions request to "${task.taskName}"`); | ||
done(); | ||
}); | ||
functions.process(task, null, processCallbackSpy); | ||
}); | ||
}); | ||
}); | ||
}); | ||
}); |
Sorry, the diff of this file is too big to display
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
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
661146
53
15031
2
5
+ Addedkinvey-code-task-runner@2.4.0(transitive)
- Removedkinvey-code-task-runner@2.3.1(transitive)