Skip to content

Commit ace962a

Browse files
Merge pull request #22 from oracle/smd_v261
Version 2.6.1
2 parents 66afb88 + 5819d32 commit ace962a

File tree

18 files changed

+1470
-1173
lines changed

18 files changed

+1470
-1173
lines changed

CUSTOM_COMPONENT.md

Lines changed: 16 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ The custom component must export two objects:
4343
- Supported transition actions
4444
- The `invoke` function, which contains the logic to execute
4545

46-
Here's an example of how to use both objects. Note that the first argument (`context`) names the reference to the [CustomComponentContext](https://oracle.github.io/bots-node-sdk/CustomComponentContext.html) object, which provides a context object for reading and changing variables as well as sending back results.
46+
Here's an example of how to use both objects. Note that the argument (`context`) names the reference to the [CustomComponentContext](https://oracle.github.io/bots-node-sdk/CustomComponentContext.html) object, which provides a context object for reading and changing variables as well as sending back results.
4747

4848
> **Note:** Before version 2.5.1, many code examples named the first argument `conversation`. Either name is valid.
4949
@@ -58,7 +58,7 @@ module.exports = {
5858
supportedActions: ['weekday', 'weekend']
5959
},
6060

61-
invoke: (context, done) => {
61+
invoke: async (context) => {
6262
// Retrieve the value of the 'human' component property.
6363
const { human } = context.properties();
6464
// determine date
@@ -69,7 +69,6 @@ module.exports = {
6969
context.reply(`Greetings ${human}`)
7070
.reply(`Today is ${now.toLocaleDateString()}, a ${dayOfWeek}`)
7171
.transition(isWeekend ? 'weekend' : 'weekday');
72-
done();
7372
}
7473
}
7574
```
@@ -90,20 +89,6 @@ module.exports = {
9089
...
9190
}
9291
```
93-
Bots Node SDK version 2.5.1 introduced an alternative syntax for the `invoke` method, which uses an `async` keyword instead of the `done` argument.
94-
95-
```javascript
96-
invoke: async (context) => {
97-
...
98-
context.reply('hello world');
99-
}
100-
```
101-
You can use this syntax in the following cases:
102-
- You'll deploy to an embedded container in a Digital Assistance instance of version 21.02 or higher
103-
- You'll deploy to a host other than the embedded container and your component package uses Bots Node SDK version 2.5.1 or higher
104-
105-
With the `async` function definition, you can write asynchronous code in a synchronous way using the `await` keyword.
106-
In addition, you no longer have to call `done()` at every place in your code where the custom component logic is completed.
10792

10893
### Using TypeScript <a name="ts">
10994

@@ -121,7 +106,7 @@ When you use TypeScript, the custom component class must implement the `CustomCo
121106
The following code shows an example of defining the two methods.
122107

123108
```typescript
124-
import {CustomComponent, CustomComponentMetadata, CustomComponentContext, InvocationCallback } from '@oracle/bots-node-sdk/lib';
109+
import {CustomComponent, CustomComponentMetadata, CustomComponentContext } from '@oracle/bots-node-sdk/lib';
125110

126111
export class HelloWorld implements CustomComponent {
127112

@@ -135,7 +120,7 @@ export class HelloWorld implements CustomComponent {
135120
}
136121
}
137122

138-
public invoke(context: CustomComponentContext, done: InvocationCallback): void {
123+
public async invoke(context: CustomComponentContext): Promise<void> {
139124
// Retrieve the value of the 'human' component property.
140125
const { human } = context.properties();
141126
// determine date
@@ -150,19 +135,6 @@ export class HelloWorld implements CustomComponent {
150135
}
151136
}
152137
```
153-
Bots Node SDK version 2.5.1 introduced an alternative syntax for the `invoke` method, which uses an `async` keyword instead of the `done` argument.
154-
155-
```typescript
156-
public async invoke(context: CustomComponentContext): Promise<void> {
157-
context.reply('hello world');
158-
}
159-
```
160-
You can use this syntax in the following cases:
161-
- You'll deploy to an embedded container in a Digital Assistance instance of version 21.02 or higher
162-
- You'll deploy to a host other than the embedded container and your component package uses Bots Node SDK version 2.5.1 or higher
163-
164-
With the `async` function definition, you can write asynchronous code in a synchronous way using the `await` keyword.
165-
In addition, you no longer have to call `done()` at every place in your code where the custom component logic is completed.
166138

167139
### The Metadata Object <a name="metadata">
168140

@@ -184,7 +156,7 @@ The `supportedActions` aren't checked at runtime. If you call the `transition(ac
184156

185157
The `invoke` method contains all the logic. In this method you can read and write skill context variables, create conversation messages, set state transitions, make REST calls, and more.
186158

187-
The first argument of the `invoke` method is the `context` object. This object references the [CustomComponentContext](https://oracle.github.io/bots-node-sdk/CustomComponentContext.html), which provides access to many convenience methods to create your logic.
159+
The argument of the `invoke` method is the `context` object. This object references the [CustomComponentContext](https://oracle.github.io/bots-node-sdk/CustomComponentContext.html), which provides access to many convenience methods to create your logic.
188160

189161
More information about creating conversation messages to send to the skill user can be found [here](https://github.com/oracle/bots-node-sdk/blob/master/MESSAGE_MODEL.md).
190162

@@ -198,12 +170,11 @@ You use different combinations of the [CustomComponentContext](https://oracle.gi
198170
If you don't call `transition()`, the response is sent but the dialog stays in the state and subsequent user input comes back to this component. That is, `invoke()` is called again.
199171

200172
```javascript
201-
invoke: (context, done) => {
173+
invoke: async (context) => {
202174
...
203175
context.reply(payload);
204176
context.keepTurn(true);
205177
context.transition ("success");
206-
done();
207178
}
208179
```
209180
Here's a list of typical combinations of `keepTurn()` and `transition()` that you can use depending on the use case:
@@ -227,52 +198,22 @@ const fetch = require("node-fetch");
227198
- **TypeScript:**
228199

229200
```typescript
230-
import * as fetch from 'node-fetch';
201+
import fetch from 'node-fetch';
231202
```
232203

233204
The code to make REST calls with `node fetch` looks like this:
234205

235-
```javascript
236-
// Make a REST GET request
237-
fetch('http://some-backend-server-url')
238-
.then((response) => {
239-
return response.json();
240-
})
241-
.then((data) => {
242-
// Store the data in a context variable
243-
context.setVariable('myContextVar', data);
244-
done();
245-
})
246-
.catch((err) => {
247-
done(err);
248-
});
249-
250-
// Make a REST POST request
251-
let payload = ...
252-
fetch('http://some-backend-server-url',{ method: 'POST', body: payload})
253-
.then((response) => {
254-
if (response.status === 200) {
255-
context.transition('success');
256-
} else {
257-
context.transition('failure');
258-
}
259-
done();
260-
})
261-
.catch((err) => {
262-
done(err);
263-
});
264-
```
265-
266-
When you use the `async invoke` syntax, you can write your code in a synchronous way without callbacks or `promise-then` constructs. For example:
267-
268206
```javascript
269207
// Make a REST GET request
270208
const response = await fetch('http://some-backend-server-url');
271209
if (response.status === 200) {
272210
const data = await response.json();
273211
// Store the data in a context variable
274212
context.setVariable('myContextVar', data);
275-
}
213+
context.transition('success');
214+
} else {
215+
context.transition('failure');
216+
}
276217

277218
// Make a REST POST request
278219
let payload = ...
@@ -300,11 +241,10 @@ module.exports = {
300241
}
301242
},
302243

303-
invoke: (context, done) => {
244+
invoke: async (context) => {
304245
// Retrieve the value of the 'name' component property.
305246
const { name } = context.properties() || '';
306247
context.reply(`Hello ${name}`);
307-
done();
308248
}
309249
}
310250
```
@@ -330,9 +270,8 @@ const { latitudeVariable } = context.properties();
330270
if (latitudeVariable) {
331271
let _latitude = context.getVariable(latitudeVariable);
332272
// ...
333-
done();
334273
} else {
335-
done(new Error('State is missing latitudeVariable property.'));
274+
throw new Error('State is missing latitudeVariable property.');
336275
}
337276
```
338277

@@ -352,15 +291,14 @@ On the skill's **Settings** tab, add the custom parameter and provide a value (o
352291
Add a `metadata` property to pass in the name of the variable, and then call `context.setVariable(<variable name>, <value>)` to set the value. For example:
353292

354293
```javascript
355-
invoke (context, done) => {
294+
invoke async (context) => {
356295
const listVariableName = context.properties().variableName;
357296
const fruits = [{"label": "Banana", "value": "banana"}, {"label": "Apple", "value": "apple"}, {"label": "Orange", "value": "orange"}];
358297
// Write list of fruits to a context variable
359298
context.setVariable(listVariableName, fruits);
360299
// Navigate to next state without first prompting for user interaction.
361300
context.keepTurn(true);
362301
context.transition();
363-
done();
364302
}
365303
```
366304

@@ -395,7 +333,7 @@ metadata: {
395333
supportedActions: ["validEmail", "invalidEmail"]
396334
},
397335

398-
invoke: (context, done) => {
336+
invoke: async (context) => {
399337
// code to get component property values and validate email goes here
400338
...
401339
// Get composite bag entity object (cbe), create bag item object, update bag item in cbe
@@ -404,7 +342,6 @@ invoke: (context, done) => {
404342
context.setVariable(variableName, cbe);
405343
context.transition("validEmail");
406344
context.keepTurn(true);
407-
done();
408345
}
409346
```
410347
> **Tip**: When working with composite bag entities, [entity event handlers](https://github.com/oracle/bots-node-sdk/blob/master/ENTITY_EVENT_HANDLER.md) are easier to use than custom components.
@@ -421,7 +358,7 @@ The payload can be a string or a rich message object. See [Conversation Messagin
421358
This code sample keeps showing the user a random quote of the day until the user indicates they want to quit.
422359

423360
```javascript
424-
invoke: (context, done) => {
361+
invoke: async (context) => {
425362

426363
const quotes = require("./json/Quotes.json");
427364
const quote = quotes[Math.floor(Math.random() * quotes.length)];
@@ -446,7 +383,6 @@ invoke: (context, done) => {
446383
// easier to see how you intend the component to behave.
447384
context.keepTurn(false);
448385
}
449-
done();
450386
}
451387
```
452388
The Quotes.json file that's used in this example looks like this:

RELEASE_NOTES.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
# Release Notes
22

3+
- [Version 2.6.1](#v261)
34
- [Version 2.6.0](#v260)
45
- [Version 2.5.5](#v255)
56
- [Version 2.5.4](#v254)
@@ -10,6 +11,17 @@
1011
- [Version 2.4.3](#v243)
1112
- [Version 2.4.2](#v242)
1213

14+
## Version 2.6.1 <a name="v261">
15+
16+
### New Features
17+
18+
- **Support for code completion in Visual Studio Code**: When using a JavaScript-based component package, you now get code insight and code completion on newly created component services when using Visual Studio Code as your editor.
19+
- **Improved custom component scaffolding**: Custom components created with the CLI now use the `async` syntax rather than the deprecated `done` callback.
20+
21+
### Fixed Issues
22+
23+
- EntityEvent interface was defined twice
24+
1325
## Version 2.6.0 <a name="v260">
1426

1527
### New Features

bin/commands/init.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,7 @@ class CCInit extends CommandDelegate {
127127
sdkBin: this.command.root()._name,
128128
expressVersion: SDK.devDependencies.express,
129129
expressTypesVersion: SDK.devDependencies['@types/express'],
130+
nodeFetchTypesVersion: SDK.devDependencies['@types/node-fetch'],
130131
typescriptVersion: SDK.devDependencies.typescript
131132
});
132133
}).then(() => { // run component code generator

bin/templates/ccpackage/ts/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
"devDependencies": {
1919
"{{sdkName}}": "^{{sdkVersion}}",
2020
"@types/express": "{{expressTypesVersion}}",
21+
"@types/node-fetch": "{{nodeFetchTypesVersion}}",
2122
"express": "{{expressVersion}}",
2223
"typescript": "{{typescriptVersion}}"
2324
},

bin/templates/components/custom/template.js

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
'use strict';
22

3+
const {CustomComponentContext} = require('@oracle/bots-node-sdk/lib'); // eslint-disable-line no-unused-vars
4+
35
// You can use your favorite http client package to make REST calls, however, the node fetch API is pre-installed with the bots-node-sdk.
46
// Documentation can be found at https://www.npmjs.com/package/node-fetch
57
// Un-comment the next line if you want to make REST calls using node-fetch.
@@ -13,7 +15,13 @@ module.exports = {
1315
},
1416
supportedActions: ['weekday', 'weekend']
1517
}),
16-
invoke: (context, done) => {
18+
19+
20+
/**
21+
* invoke methods gets called when the custom component state is executed in the dialog flow
22+
* @param {CustomComponentContext} context
23+
*/
24+
invoke: async (context) => {
1725
// Retrieve the value of the 'human' component property.
1826
const { human } = context.properties();
1927
// Determine the current date
@@ -24,6 +32,5 @@ module.exports = {
2432
context.reply(`Greetings ${human}`)
2533
.reply(`Today is ${now.toLocaleDateString()}, a ${dayOfWeek}`)
2634
.transition(isWeekend ? 'weekend' : 'weekday');
27-
done();
2835
}
2936
};

bin/templates/components/custom/template.ts

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1-
import {CustomComponent, CustomComponentMetadata, CustomComponentContext, InvocationCallback } from '@oracle/bots-node-sdk/lib';
1+
import {CustomComponent, CustomComponentMetadata, CustomComponentContext} from '@oracle/bots-node-sdk/lib';
22

33
// You can use your favorite http client package to make REST calls, however, the node fetch API is pre-installed with the bots-node-sdk.
44
// Documentation can be found at https://www.npmjs.com/package/node-fetch
55
// Un-comment the next line if you want to make REST calls using node-fetch.
6-
// import * as fetch from 'node-fetch';
6+
// import fetch from 'node-fetch';
77

88
export class {{className}} implements CustomComponent {
99

@@ -17,7 +17,7 @@ export class {{className}} implements CustomComponent {
1717
};
1818
}
1919

20-
public invoke(context: CustomComponentContext, done: InvocationCallback): void {
20+
public async invoke(context: CustomComponentContext): Promise<void> {
2121
// Retrieve the value of the 'human' component property.
2222
const { human } = context.properties();
2323
// Determine the current date
@@ -28,7 +28,6 @@ export class {{className}} implements CustomComponent {
2828
context.reply(`Greetings ${human}`)
2929
.reply(`Today is ${now.toLocaleDateString()}, a ${dayOfWeek}`)
3030
.transition(isWeekend ? 'weekend' : 'weekday');
31-
done();
3231
}
3332

3433
}

bin/templates/components/entityeventhandler/template.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
'use strict';
22

3+
const {EntityPublishMessageEvent, EntityBaseEvent, EntityResolutionContext} = require('@oracle/bots-node-sdk/lib'); // eslint-disable-line no-unused-vars
4+
35
// You can use your favorite http client package to make REST calls, however, the node fetch API is pre-installed with the bots-node-sdk.
46
// Documentation can be found at https://www.npmjs.com/package/node-fetch
57
// Un-comment the next line if you want to make REST calls using node-fetch.
@@ -16,6 +18,8 @@ module.exports = {
1618
/**
1719
* Default message handler that includes acknowledgements when a bag item is updated
1820
* or a bag item value is provided while the user was prompted for another item
21+
* @param {EntityPublishMessageEvent} event
22+
* @param {EntityResolutionContext} context
1923
*/
2024
publishMessage: async (event, context) => {
2125
updatedItemsMessage(context);
@@ -24,6 +28,8 @@ module.exports = {
2428
},
2529
/**
2630
* This handler is called when the composite bag entity is resolved
31+
* @param {EntityBaseEvent} event
32+
* @param {EntityResolutionContext} context
2733
*/
2834
resolved: async (event, context) => { // eslint-disable-line no-unused-vars
2935
// add your back-end REST API call here
@@ -44,6 +50,7 @@ module.exports = {
4450

4551
/**
4652
* Helper function to show acknowledgement message when a bag item value is updated.
53+
* @param {EntityResolutionContext} context
4754
*/
4855
function updatedItemsMessage(context) {
4956
if (context.getItemsUpdated().length > 0) {
@@ -54,6 +61,7 @@ function updatedItemsMessage(context) {
5461

5562
/**
5663
* Helper function to show acknowledgement message when a bag item value is provided when user was prompted for anther bag item.
64+
* @param {EntityResolutionContext} context
5765
*/
5866
function outOfOrderItemsMessage(context) {
5967
if (context.getItemsMatchedOutOfOrder().length > 0) {

0 commit comments

Comments
 (0)