camunda-external-task-client-js
Advanced tools
Comparing version 0.2.0 to 1.0.0
# Changelog | ||
## 0.1.0-alpha2 | ||
## 1.0.0 | ||
### Features | ||
- Filter tasks by business key | ||
### Bug Fixes | ||
- Setting typed date variable with a string value causes serialization issue | ||
## 0.2.0 | ||
### Features | ||
- Setting Local Variables | ||
- Support for File & Date Variables | ||
## 0.1.1 | ||
### Features | ||
- Exchange Process Variables | ||
## 0.1.0-alpha1 | ||
## 0.1.0 | ||
@@ -16,2 +28,2 @@ ### Features | ||
- Extend Lock | ||
- Unlock | ||
- Unlock |
@@ -63,6 +63,7 @@ # `Client` | ||
| Option | Description | Type | Required | Default | | ||
| ------------ | ------------------------------------------------------- | ------ | -------- | ----------------------------------------------------- | | ||
| lockDuration | specifies the lock duration for this specific handler. | number | | global lockDuration configured in the client instance | | ||
| variables | defines a subset of variables available in the handler. | array | | global lockDuration configured in the client instance | | ||
| Option | Description | Type | Required | Default | | ||
|--------------|-------------------------------------------------------------------------------------|--------|----------|-------------------------------------------------------| | ||
| lockDuration | specifies the lock duration for this specific handler. | number | | global lockDuration configured in the client instance | | ||
| variables | defines a subset of variables available in the handler. | array | | global lockDuration configured in the client instance | | ||
| businessKey | A value which allows to filter tasks based on process instance business key | string | | | | ||
@@ -69,0 +70,0 @@ |
@@ -212,13 +212,7 @@ # Variables | ||
## About JSON & Date Variables | ||
Date and JSON values are automatically serialized when being set and deserialized when being read. | ||
### Date | ||
Date values are automatically parsed to the date format supported by the engine when | ||
completing a task. | ||
Moreover, dates are always available in the string format in the `task.variables` | ||
object. | ||
```js | ||
// `task.variables.get("aDate")`returns a string | ||
console.log( typeof task.variables.get("aDate") ); // output: "string" | ||
// 'variables.set()' can be used to set a date by providing a date object | ||
@@ -231,9 +225,12 @@ variables.set("someDate", new Date()); | ||
// 2- providing a date string as a value: | ||
variables.setTyped("anotherDate", { type: "date", value: "31 march 1994", valueInfo: {} }); | ||
variables.setTyped("anotherDate", { type: "date", value: "2016-01-25T13:33:42.165+0100", valueInfo: {} }); | ||
// `variables.get("anotherDate")` is a date object | ||
console.log(typeof variables.get("anotherDate")); // output: object | ||
// `variables.getTyped("anotherDate").value` is date object | ||
console.log(typeof variables.getTyped("anotherDate").value); // output: object | ||
``` | ||
### JSON | ||
JSON variables are automatically converted to string when completing a task. | ||
They are also parsed to objects when polling variables. | ||
```js | ||
@@ -250,4 +247,7 @@ // 'variables.set()' can be used to set a JSON object by providing an object | ||
// `variables.get("meal")`returns an object | ||
// `variables.get("meal")` is an object | ||
console.log(variables.get("someJSON")); // output: { id: 0, name: "pasta" } | ||
// `variables.getTyped("meal").value` is an object | ||
console.log(variables.getTyped("someJSON").value); // output: { id: 0, name: "pasta" } | ||
``` |
@@ -5,3 +5,3 @@ const { | ||
Variables | ||
} = require("camunda-external-task-handler-js"); | ||
} = require("camunda-external-task-client-js"); | ||
@@ -11,3 +11,6 @@ // configuration for the Client: | ||
// - 'logger': utility to automatically log important events | ||
const config = { baseUrl: "http://localhost:8080/engine-rest", use: logger }; | ||
const config = { | ||
baseUrl: "http://localhost:8080/engine-rest", | ||
use: logger | ||
}; | ||
@@ -24,3 +27,5 @@ // create a Client instance with custom configuration | ||
const creditScores = [defaultScore, 9, 1, 4, 10]; | ||
const processVariables = new Variables().set("creditScores", creditScores); | ||
const processVariables = new Variables() | ||
.set("creditScores", creditScores) | ||
.set("bar", new Date()); | ||
@@ -38,1 +43,6 @@ // complete the task | ||
client.subscribe("creditScoreChecker", handler); | ||
client.subscribe("requestRejecter", async ({ task, taskService }) => { | ||
console.log(task.variables.get("bar")); | ||
console.log(task.variables.get("creditScores")); | ||
}); |
@@ -8,4 +8,4 @@ { | ||
"dependencies": { | ||
"camunda-external-task-client-js": "^0.1.0" | ||
"camunda-external-task-client-js": "^0.2.0" | ||
} | ||
} |
@@ -111,2 +111,48 @@ const File = require("../File"); | ||
const deserializeVariable = ({ | ||
key, | ||
typedValue, | ||
processInstanceId, | ||
engineService | ||
}) => { | ||
let { value, type } = { ...typedValue }; | ||
type = type.toLowerCase(); | ||
if (type === "json") { | ||
value = JSON.parse(value); | ||
} | ||
if (type === "file") { | ||
let remotePath = `/execution/${processInstanceId}/localVariables/${key}/data`; | ||
value = new File({ typedValue, remotePath, engineService }); | ||
} | ||
if (type === "date") { | ||
value = new Date(value); | ||
} | ||
return { ...typedValue, value, type }; | ||
}; | ||
const serializeVariable = ({ key, typedValue }) => { | ||
let { value, type } = { ...typedValue }; | ||
type = type.toLowerCase(); | ||
if (type === "file" && value instanceof File) { | ||
return value.createTypedValue(); | ||
} | ||
if (type === "json" && typeof value !== "string") { | ||
value = JSON.stringify(value); | ||
} | ||
if (type === "date" && value instanceof Date) { | ||
value = value.toISOString().replace(/Z$/, "UTC+00:00"); | ||
} | ||
return { ...typedValue, value, type }; | ||
}; | ||
module.exports = { | ||
@@ -118,3 +164,5 @@ isFunction, | ||
getVariableType, | ||
mapEntries | ||
mapEntries, | ||
serializeVariable, | ||
deserializeVariable | ||
}; |
@@ -7,6 +7,8 @@ const { | ||
getVariableType, | ||
mapEntries | ||
mapEntries, | ||
deserializeVariable, | ||
serializeVariable | ||
} = require("./utils"); | ||
const FileService = require("../File"); | ||
const File = require("../File"); | ||
@@ -98,4 +100,4 @@ describe("utils", () => { | ||
test("getVariableType(new FileService) should be file", () => { | ||
const file = new FileService({ localPath: "foo" }); | ||
test("getVariableType(new File) should be file", () => { | ||
const file = new File({ localPath: "foo" }); | ||
expect(getVariableType(file)).toBe("file"); | ||
@@ -124,2 +126,143 @@ }); | ||
}); | ||
describe("deserializeVariable", () => { | ||
it("value should remain the same if type is neither file, json nor date", () => { | ||
// given | ||
let typedValue = { value: "some value", type: "string", valueInfo: {} }; | ||
// then | ||
expect(deserializeVariable({ typedValue })).toMatchObject(typedValue); | ||
}); | ||
it("value should be parsed if type is JSON", () => { | ||
// given | ||
let parsedValue = { x: 10 }; | ||
let typedValue = { | ||
value: JSON.stringify(parsedValue), | ||
type: "json", | ||
valueInfo: {} | ||
}; | ||
let expectedTypedValue = { ...typedValue, value: parsedValue }; | ||
// then | ||
expect(deserializeVariable({ typedValue })).toMatchObject( | ||
expectedTypedValue | ||
); | ||
}); | ||
it("value should be a File instance if type is file", () => { | ||
// given | ||
let typedValue = { value: "", type: "File", valueInfo: {} }; | ||
let options = { | ||
key: "variable_key", | ||
typedValue, | ||
processInstanceId: "process_instance_id", | ||
engineService: {} | ||
}; | ||
let result = deserializeVariable(options); | ||
// then | ||
// the value should be a file | ||
expect(result.value).toBeInstanceOf(File); | ||
// match file parameters to snapshot | ||
expect(result).toMatchSnapshot(); | ||
}); | ||
it("value should become a Date object if type is date", () => { | ||
// given | ||
let dateStr = "2013-06-30T21:04:22.000+0200"; | ||
let dateObj = new Date(dateStr); | ||
let typedValue = { | ||
value: dateStr, | ||
type: "Date", | ||
valueInfo: {} | ||
}; | ||
// then | ||
expect(deserializeVariable({ typedValue }).value).toMatchObject(dateObj); | ||
}); | ||
}); | ||
describe("serializeVariable", () => { | ||
it("value should remain the same if type is neither file, json nor date", () => { | ||
// given | ||
let typedValue = { value: 21, type: "integer", valueInfo: {} }; | ||
// then | ||
expect(serializeVariable({ typedValue })).toMatchObject(typedValue); | ||
}); | ||
it("value should be stringifyed if type is JSON and value is not a string", () => { | ||
// given | ||
let parsedValue = { x: 10 }; | ||
let typedValue = { | ||
value: parsedValue, | ||
type: "json", | ||
valueInfo: {} | ||
}; | ||
let expectedTypedValue = { | ||
...typedValue, | ||
value: JSON.stringify(parsedValue) | ||
}; | ||
// then | ||
expect(serializeVariable({ typedValue })).toMatchObject( | ||
expectedTypedValue | ||
); | ||
}); | ||
it("value should remain the same if type is JSON and value is a string", () => { | ||
// given | ||
let value = JSON.stringify({ x: 10 }); | ||
let typedValue = { | ||
value, | ||
type: "json", | ||
valueInfo: {} | ||
}; | ||
// then | ||
expect(serializeVariable({ typedValue })).toMatchObject(typedValue); | ||
}); | ||
it("should return result of createTypedValue if instance if type is file and value is an instance of File", () => { | ||
// given | ||
let value = new File({ localPath: "some/path" }); | ||
let createTypedValueSpy = jest.spyOn(value, "createTypedValue"); | ||
let typedValue = { value, type: "File", valueInfo: {} }; | ||
let result = serializeVariable({ typedValue }); | ||
// then | ||
// createTypedValue should be called | ||
expect(createTypedValueSpy).toBeCalled(); | ||
// result must be the result of createTypedValue | ||
expect(result).toMatchObject(value.createTypedValue()); | ||
}); | ||
it("value should remain the same if instance if type is file and value is not an instance of File", () => { | ||
// given | ||
let value = "some value"; | ||
let typedValue = { value, type: "file", valueInfo: {} }; | ||
let result = serializeVariable({ typedValue }); | ||
// then | ||
expect(result).toMatchObject(typedValue); | ||
}); | ||
it("value should be converted to proper formatted string if type is date and value is an instance of date", () => { | ||
// given | ||
let dateStr = "2013-06-30T21:04:22.000+0200"; | ||
let formattedDate = "2013-06-30T19:04:22.000UTC+00:00"; | ||
let dateObj = new Date(dateStr); | ||
let typedValue = { | ||
value: dateObj, | ||
type: "Date", | ||
valueInfo: {} | ||
}; | ||
// then | ||
expect(serializeVariable({ typedValue }).value).toBe(formattedDate); | ||
}); | ||
}); | ||
}); |
@@ -15,3 +15,7 @@ const events = require("events"); | ||
const { isFunction, isArrayOfFunctions } = require("./__internal/utils"); | ||
const { | ||
isFunction, | ||
isArrayOfFunctions, | ||
isUndefinedOrNull | ||
} = require("./__internal/utils"); | ||
@@ -144,8 +148,18 @@ const defaultOptions = { | ||
// collect topics that have subscriptions | ||
const topics = Object.keys(topicSubscriptions).map(topicName => ({ | ||
topicName, | ||
lockDuration: topicSubscriptions[topicName].lockDuration, | ||
variables: topicSubscriptions[topicName].variables | ||
})); | ||
const topics = Object.entries(topicSubscriptions).map( | ||
([topicName, { lockDuration, variables, businessKey }]) => { | ||
let topic = { topicName, lockDuration }; | ||
if (!isUndefinedOrNull(variables)) { | ||
topic.variables = variables; | ||
} | ||
if (!isUndefinedOrNull(businessKey)) { | ||
topic.businessKey = businessKey; | ||
} | ||
return topic; | ||
} | ||
); | ||
const requestBody = { ...pollingOptions, topics }; | ||
@@ -152,0 +166,0 @@ |
@@ -38,2 +38,3 @@ const fs = require("fs"); | ||
this.filename = this.filename || path.basename(remotePath || localPath); | ||
this.content = ""; | ||
} | ||
@@ -40,0 +41,0 @@ |
@@ -1,51 +0,13 @@ | ||
const { getVariableType, mapEntries } = require("./__internal/utils"); | ||
const { | ||
getVariableType, | ||
mapEntries, | ||
serializeVariable, | ||
deserializeVariable | ||
} = require("./__internal/utils"); | ||
const File = require("./File"); | ||
function Variables(initialVariables = {}, options = {}) { | ||
const { readOnly, processInstanceId, engineService } = options; | ||
/** | ||
* formats a variable received from the engine or sent to the engine | ||
* @param variable.key | ||
* @param variable.typedValue | ||
* @param options.direction | ||
*/ | ||
const formatVariable = ({ key, value: typedValue }, { direction }) => { | ||
let { type, value, valueInfo } = { ...typedValue }; | ||
type = type.toLowerCase(); | ||
const remotePath = `/execution/${processInstanceId}/localVariables/${key}/data`; | ||
switch (type) { | ||
case "json": | ||
if (direction === "fromString" && typeof value === "string") { | ||
value = JSON.parse(value); | ||
} else if (direction === "toString") { | ||
value = JSON.stringify(value); | ||
} | ||
break; | ||
case "file": | ||
if (direction === "fromString") { | ||
value = new File({ typedValue, remotePath, engineService }); | ||
} else { | ||
({ value, valueInfo } = value.createTypedValue()); | ||
} | ||
break; | ||
case "date": | ||
value = value.toISOString().replace(/Z$/, "UTC+00:00"); | ||
break; | ||
default: | ||
} | ||
return { [key]: { type, value, valueInfo } }; | ||
}; | ||
let dirtyVariables = {}; | ||
let variables = mapEntries(initialVariables, variable => | ||
formatVariable(variable, { direction: "fromString" }) | ||
); | ||
/** | ||
@@ -56,9 +18,14 @@ * @returns the typedValue corresponding to variableName | ||
this.getTyped = variableName => { | ||
let variable = variables[variableName]; | ||
let typedValue = initialVariables[variableName]; | ||
if (!variable) { | ||
if (!typedValue) { | ||
return null; | ||
} | ||
return { ...variable }; | ||
return deserializeVariable({ | ||
key: variableName, | ||
typedValue, | ||
processInstanceId, | ||
engineService | ||
}); | ||
}; | ||
@@ -79,3 +46,3 @@ | ||
this.getAll = () => | ||
mapEntries(variables, ({ key }) => ({ [key]: this.get(key) })); | ||
mapEntries(initialVariables, ({ key }) => ({ [key]: this.get(key) })); | ||
@@ -86,3 +53,3 @@ /** | ||
this.getAllTyped = () => | ||
mapEntries(variables, ({ key }) => ({ [key]: this.getTyped(key) })); | ||
mapEntries(initialVariables, ({ key }) => ({ [key]: this.getTyped(key) })); | ||
@@ -93,5 +60,3 @@ /** | ||
this.getDirtyVariables = () => { | ||
return mapEntries(dirtyVariables, variable => | ||
formatVariable(variable, { direction: "toString" }) | ||
); | ||
return dirtyVariables; | ||
}; | ||
@@ -106,9 +71,8 @@ | ||
this.setTyped = (variableName, typedValue) => { | ||
let { value, type } = { ...typedValue }; | ||
type = type && type.toLowerCase(); | ||
variables[variableName] = dirtyVariables[variableName] = { | ||
...typedValue, | ||
value, | ||
type | ||
}; | ||
initialVariables[variableName] = dirtyVariables[ | ||
variableName | ||
] = serializeVariable({ | ||
key: variableName, | ||
typedValue | ||
}); | ||
return this; | ||
@@ -115,0 +79,0 @@ }; |
{ | ||
"version": "0.2.0", | ||
"version": "1.0.0", | ||
"name": "camunda-external-task-client-js", | ||
@@ -4,0 +4,0 @@ "main": "index.js", |
@@ -143,29 +143,29 @@ # camunda-external-task-client | ||
* [Client](/docs/Client.md) | ||
* [new Client(options)](/docs/Client.md#new-clientoptions) | ||
* [client.start()](/docs/Client.md#clientstart) | ||
* [client.subscribe(topic, [options], handler)](/docs/Client.md#clientsubscribetopic-options-handler) | ||
* [client.stop()](/docs/Client.md#clientstop) | ||
* [Client Events)](/docs/Client.md#client-events) | ||
* [About the Handler Function](/docs/handler.md) | ||
* [Variables](/docs/Variables.md) | ||
* [new Variables(options)](/docs/Variables.md#new-variablesoptions") | ||
* [variables.get(variableName)](/docs/Variables.md#variablesgetvariablename) | ||
* [variables.getTyped(variableName)](/docs/Variables.md#variablesgettypedvariablename) | ||
* [variables.getAll()](/docs/Variables.md#variablesgetall) | ||
* [variables.getAllTyped()](/docs/Variables.md#variablesgetalltyped) | ||
* [variables.set(variableName)](/docs/Variables.md#variablessetvariablename-value) | ||
* [variables.setTyped(variableName)](/docs/Variables.md#variablessettypedvariablename-typedvalue) | ||
* [variables.setAll(values)](/docs/Variables.md#variablessetallvalues) | ||
* [variables.setAllTyped(typedValues)](/docs/Variables.md#variablessetalltypedtypedvalues) | ||
* [About JSON & Date Variables](/docs/Variables.md#about-json--date-variables) | ||
* [File](/docs/File.md) | ||
* [new File(options)](/docs/File.md#new-fileoptions) | ||
* [file.load()](/docs/File.md#fileload) | ||
* [File Properties](/docs/File.md#file-properties) | ||
* [BasicAuthInterceptor](/docs/BasicAuthInterceptor.md) | ||
* [new BasicAuthInterceptor(options)](/docs/BasicAuthInterceptor.md#new-basicauthinterceptoroptions) | ||
* [logger](/docs/logger.md) | ||
* [logger.success(text)](/docs/logger.md#loggersuccesstext) | ||
* [logger.error(text)](/docs/logger.md#loggererrortext) | ||
* [Client](https://github.com/camunda/camunda-external-task-client-js/blob/master/docs/Client.md) | ||
* [new Client(options)](https://github.com/camunda/camunda-external-task-client-js/blob/master/docs/Client.md#new-clientoptions) | ||
* [client.start()](https://github.com/camunda/camunda-external-task-client-js/blob/master/docs/Client.md#clientstart) | ||
* [client.subscribe(topic, [options], handler)](https://github.com/camunda/camunda-external-task-client-js/blob/master/docs/Client.md#clientsubscribetopic-options-handler) | ||
* [client.stop()](https://github.com/camunda/camunda-external-task-client-js/blob/master/docs/Client.md#clientstop) | ||
* [Client Events)](https://github.com/camunda/camunda-external-task-client-js/blob/master/docs/Client.md#client-events) | ||
* [About the Handler Function](https://github.com/camunda/camunda-external-task-client-js/blob/master/docs/handler.md) | ||
* [Variables](https://github.com/camunda/camunda-external-task-client-js/blob/master/docs/Variables.md) | ||
* [new Variables(options)](https://github.com/camunda/camunda-external-task-client-js/blob/master/docs/Variables.md#new-variablesoptions") | ||
* [variables.get(variableName)](https://github.com/camunda/camunda-external-task-client-js/blob/master/docs/Variables.md#variablesgetvariablename) | ||
* [variables.getTyped(variableName)](https://github.com/camunda/camunda-external-task-client-js/blob/master/docs/Variables.md#variablesgettypedvariablename) | ||
* [variables.getAll()](https://github.com/camunda/camunda-external-task-client-js/blob/master/docs/Variables.md#variablesgetall) | ||
* [variables.getAllTyped()](https://github.com/camunda/camunda-external-task-client-js/blob/master/docs/Variables.md#variablesgetalltyped) | ||
* [variables.set(variableName)](https://github.com/camunda/camunda-external-task-client-js/blob/master/docs/Variables.md#variablessetvariablename-value) | ||
* [variables.setTyped(variableName)](https://github.com/camunda/camunda-external-task-client-js/blob/master/docs/Variables.md#variablessettypedvariablename-typedvalue) | ||
* [variables.setAll(values)](https://github.com/camunda/camunda-external-task-client-js/blob/master/docs/Variables.md#variablessetallvalues) | ||
* [variables.setAllTyped(typedValues)](https://github.com/camunda/camunda-external-task-client-js/blob/master/docs/Variables.md#variablessetalltypedtypedvalues) | ||
* [About JSON & Date Variables](https://github.com/camunda/camunda-external-task-client-js/blob/master/docs/Variables.md#about-json--date-variables) | ||
* [File](https://github.com/camunda/camunda-external-task-client-js/blob/master/docs/File.md) | ||
* [new File(options)](https://github.com/camunda/camunda-external-task-client-js/blob/master/docs/File.md#new-fileoptions) | ||
* [file.load()](https://github.com/camunda/camunda-external-task-client-js/blob/master/docs/File.md#fileload) | ||
* [File Properties](https://github.com/camunda/camunda-external-task-client-js/blob/master/docs/File.md#file-properties) | ||
* [BasicAuthInterceptor](https://github.com/camunda/camunda-external-task-client-js/blob/master/docs/BasicAuthInterceptor.md) | ||
* [new BasicAuthInterceptor(options)](https://github.com/camunda/camunda-external-task-client-js/blob/master/docs/BasicAuthInterceptor.md#new-basicauthinterceptoroptions) | ||
* [logger](https://github.com/camunda/camunda-external-task-client-js/blob/master/docs/logger.md) | ||
* [logger.success(text)](https://github.com/camunda/camunda-external-task-client-js/blob/master/docs/logger.md#loggersuccesstext) | ||
* [logger.error(text)](https://github.com/camunda/camunda-external-task-client-js/blob/master/docs/logger.md#loggererrortext) | ||
@@ -172,0 +172,0 @@ ## License |
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
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
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
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
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
1638553
63
3086
0
0