diff --git a/Changes.md b/Changes.md
index 9c5627c..a06cc89 100644
--- a/Changes.md
+++ b/Changes.md
@@ -1,119 +1,22 @@
# Changes
-## 2.0.0 Beta: Async/Await
+## 2.0.0: The Async/Await Update
This is a major new version of RiveScript. It adds async/await support and
makes the API asynchronous everywhere. It also decaffeinates the code,
migrating it from CoffeeScript back to native ES2015+ with modern syntax.
-### Backwards Incompatible Changes
-
-* The `reply()` method now returns a Promise instead of a string. In that
- regard, it works just like the old `replyAsync()` method did.
-* The `loadFile()` and `loadDirectory()` functions return Promises now
- instead of using callbacks.
-* The `replyAsync()` method is now deprecated in favor of `reply()`.
-
-The user variable session manager is now pluggable and replaceable, with
-the default continuing to be in-memory storage of user variables.
-
-For session managers to support async database drivers, all of the user
-variable functions now return their result as a Promise:
-
-* `setUservar(user, name, value)`
-* `setUservars(user, data)`
-* `getUservar(user, name)`
-* `getUservars([user])`
-* `clearUservars([user])`
-* `freezeUservars(user)`
-* `thawUservars(user, action="thaw")`
-* `lastMatch(user)`
-* `initialMatch(user)`
-* `lastTriggers(user)`
-* `getUserTopicTriggers(user)`
-
-### User Variable Session Managers
-
-RiveScript-JS finally joins its Python, Go, and Java cousins in supporting
-pluggable user variable session managers.
-
-This feature will allow you to replace the default in-memory user variable
-store with one backed by a database, like MongoDB or Redis.
-
-```javascript
-// MemorySessionManager is the default session store, but you
-// could implement Redis or anything by making a SessionManager
-// compatible class.
-const { MemorySessionManager } = require("./src/sessions");
-
-// Use your session manager.
-var bot = new RiveScript({
- sessionManager: new MemorySessionManager()
-});
-```
-
-See the [sessions](./sessions.md) documentation for more details.
-
-### Async Objects in Conditions
-
-Async/Await enables asynchronous object macros that return Promises to
-be used *anywhere* throughout RiveScript. This means they can finally be
-used inside of `*Condition`s! Example:
-
-```rivescript
-// wait-limited $timeout $maxTimeout
-// If the $timeout > $maxTimeout, it resolves "too long" immediately.
-// Otherwise it waits $timeout seconds and resolves "done"
-> object wait-limited javascript
- var timeout = parseInt(args[0]);
- var max = parseInt(args[1]);
-
- return new Promise(function(resolve, reject) {
- if (timeout > max) {
- resolve("too long");
- } else {
- setTimeout(function() {
- resolve("done");
- }, timeout*1000);
- }
- });
-< object
-
-+ can you wait # seconds
-* wait-limited 6 == done => I can!
-- No the longest I'll wait is 6 seconds.
-```
-
-### Upgrading
-
-To support the async features, the RiveScript API had to break backward
-compatibility.
-
-The `reply()` function now returns a Promise instead of the string
-result. It works like `replyAsync()` did before; and so now `replyAsync()`
-is a deprecated function.
-
-Here is an example of how to migrate your code if you were using `reply()`
-before to get the string reply:
-
-```diff
-- var reply = bot.reply(username, message, this);
-- console.log("Bot>", reply);
-+ rs.reply(username, message, this).then(function(reply) {
- console.log("Bot>", reply);
-+ })
-```
-
-Likewise, the `loadDirectory()` and `loadFile()` functions were made
-to be Promise-based instead of callback-based. Switching over is simple:
-
-```diff
-- bot.loadDirectory("./brain", onSuccess, onError);
-+ bot.loadDirectory("./brain").then(onSuccess).catch(onError);
-
-- bot.loadFile("./brain/admin.rive", onSuccess, onError);
-+ bot.loadFile("./brain/admin.rive").then(onSuccess).catch(onError);
-```
+See the [Upgrading-v2](https://github.com/aichaos/rivescript-js/blob/master/Upgrading-v2.md) document for information about what's
+new and how to upgrade your code.
+
+v2.0.0 last minute changes:
+
+- Fix a bug where `` in `+Trigger` wasn't being formatted properly
+ (lowercased, etc.) so matching was difficult.
+- Add a Redis driver for an example User Variable Session Manager that
+ stores variables directly to the cache, and an `eg/redis` example bot
+ that demonstrates it.
+- Write documentation for final v2.0.0 launch.
### 2.0.0-beta.1 - Jan 16 2019
diff --git a/README.md b/README.md
index 7e9f1f4..37c9a82 100644
--- a/README.md
+++ b/README.md
@@ -11,6 +11,20 @@ pairs for building up a bot's intelligence.
This library can be used both in a web browser or as a Node module.
See the `eg/` folder for examples.
+## NOTICE: CHANGES IN v2.0.0
+
+RiveScript v2.0.0 comes with a **massive** refactor of the codebase to
+implement modern Async/Await features all throughout. The refactor now
+allows features like "storing user variables directly in Redis" or
+"using asynchronous macros in conditionals"
+
+But it necessarily had to break some backwards compatibility -- slightly!
+-- by turning previously synchronous functions like `reply()` into
+async ones that return Promises like `replyAsync()` did.
+
+See the [Upgrading-v2](https://github.com/aichaos/rivescript-js/blob/master/Upgrading-v2.md) document for information on the changes
+and how to fix your code for the new version.
+
## USAGE
```javascript
@@ -80,37 +94,6 @@ Both shell scripts accept command line parameters:
When using RiveScript.js as a library, the synopsis is as follows:
-## NOTICE: CHANGES IN v2.0.0
-
-RiveScript v2.0.0 comes with a **massive** refactor of the codebase to
-implement modern Async/Await features all throughout. This refactor
-enables the following **new features**:
-
-* You can now `` asynchronous object macros inside of `*Condition`
- checks.
-* You can **actively** store users' variables into a database or
- Redis cache. The module `rivescript-redis` provides a Redis cache
- driver for this feature and there's an example bot at
- [eg/redis](https://github.com/aichaos/rivescript-js/tree/master/eg/redis).
- Other drivers (MongoDB, etc.) are up to you to write (send a pull
- request! Use the Redis driver as an example)
-
-Because everything had to upgrade to async functions for this to work,
-it necessarily had to break backwards compatibility slightly:
-
-* **reply()** now returns a Promise instead of a string, like replyAsync()
- has always done.
-* All user variable functions (getUservars, setUservars, etc.) now return
- a Promise rather than their values directly; this change is what makes
- it possible to swap out async database drivers instead of the default
- in-memory store!
-* **loadFile()** and **loadDirectory()** now return Promises. However, the
- old callback-based syntax still works but is now deprecated.
-* **replyAsync()** is now deprecated in favor of just **reply()** since
- they both do the same thing.
-
-See the [Change Log](https://github.com/aichaos/rivescript-js/blob/master/Changes.md) for more details.
-
## DOCUMENTATION
There is generated Markdown and HTML documentation of the modules in the
diff --git a/Upgrading-v2.md b/Upgrading-v2.md
index d65ff9f..b078038 100644
--- a/Upgrading-v2.md
+++ b/Upgrading-v2.md
@@ -15,6 +15,85 @@ The major highlights of the RiveScript v2.0.0 release are:
syntax. CoffeeScript was holding us back from the `await` keyword
and JavaScript is actually nice to program in nowadays.
+# New Features
+
+## User Variables Session Managers
+
+Previously, RiveScript only stored user variables in its own process
+memory (keyed by username), and if you wanted the bot to remember user
+information across reboots, you needed to use functions like getUservars
+and setUservars to get data in and out of the bot's memory.
+
+With the new Async/Await features, now, it is possible to replace the
+User Variable Session Manager with a more active one, such as a Redis
+cache or a MongoDB database. So every time a user variable gets ``,
+it's put directly into a database rather than just kept in memory.
+
+The default is still an in-memory store, but you can implement a custom
+async driver following the SessionManager interface. There is a Redis
+driver in the rivescript-js git repository called `rivescript-redis`
+
+```javascript
+// Import rivescript and rivescript-redis
+const RiveScript = require("rivescript"),
+ RedisSessionManager = require("rivescript-redis");
+
+// Construct your RiveScript bot as normal...
+let bot = new RiveScript({
+ utf8: true,
+
+ // Give it a new Redis session manager.
+ sessionManager: new RedisSessionManager({
+ // The constructor takes an `opts` object, and mostly passes it
+ // directly along to the underlying `redis` module. So all these
+ // parameters come from `redis`
+ host: "localhost", // default
+ port: 6369,
+
+ // NOTE: this option is used by `redis` and is also noticed by
+ // rivescript-redis: it's optional but recommended to set a
+ // prefix. The Redis keys otherwise are simply the username
+ // given to RiveScript.
+ prefix: "rivescript/"
+ })
+});
+
+// And carry on as normal. All user variables will be actively persisted
+// in Redis (no need to call `getUservars()` and `setUservars()` to manage
+// them yourself -- though these functions DO work and will get you current
+// data from your Redis cache!)
+```
+
+# Async Objects in Conditions
+
+Async/Await enables asynchronous object macros that return Promises to
+be used *anywhere* throughout RiveScript. This means they can finally be
+used inside of `*Condition`s! Example:
+
+```rivescript
+// wait-limited $timeout $maxTimeout
+// If the $timeout > $maxTimeout, it resolves "too long" immediately.
+// Otherwise it waits $timeout seconds and resolves "done"
+> object wait-limited javascript
+ var timeout = parseInt(args[0]);
+ var max = parseInt(args[1]);
+
+ return new Promise(function(resolve, reject) {
+ if (timeout > max) {
+ resolve("too long");
+ } else {
+ setTimeout(function() {
+ resolve("done");
+ }, timeout*1000);
+ }
+ });
+< object
+
++ can you wait # seconds
+* wait-limited 6 == done => I can!
+- No the longest I'll wait is 6 seconds.
+```
+
# JavaScript API Changes
## Changed: reply() now returns a Promise
@@ -136,10 +215,6 @@ bot.setUservar(user, "name", "Alice").then(() => {
});
```
-# Background
-
-TBD.
-
[1]: https://github.com/aichaos/rivescript-js
[2]: https://www.twilio.com/blog/2015/10/asyncawait-the-hero-javascript-deserved.html
[3]: https://github.com/aichaos/rivescript-js/commit/2e6aae30bbecd4cba946ef95b085f023954dcb97?w=1
diff --git a/contrib/redis/README.md b/contrib/redis/README.md
new file mode 100644
index 0000000..98f163b
--- /dev/null
+++ b/contrib/redis/README.md
@@ -0,0 +1,54 @@
+# Redis for RiveScript
+
+```
+npm install rivescript-redis
+```
+
+This module implements a Redis cache driver for the RiveScript User Variable
+Session Manager.
+
+It lets you **actively** persist your user variables to Redis instead of
+just in the bot's memory, so that your bot can easily recall user
+information across reboots and even across separate machines by storing
+them in Redis.
+
+This module is part of the `rivescript-js` project which can be found at
+https://github.com/aichaos/rivescript-js and is released under the same
+license (MIT).
+
+## Usage
+
+```javascript
+// Import rivescript and rivescript-redis
+const RiveScript = require("rivescript"),
+ RedisSessionManager = require("rivescript-redis");
+
+// Construct your RiveScript bot as normal...
+let bot = new RiveScript({
+ utf8: true,
+
+ // Give it a new Redis session manager.
+ sessionManager: new RedisSessionManager({
+ // The constructor takes an `opts` object, and mostly passes it
+ // directly along to the underlying `redis` module. So all these
+ // parameters come from `redis`
+ host: "localhost", // default
+ port: 6369,
+
+ // NOTE: this option is used by `redis` and is also noticed by
+ // rivescript-redis: it's optional but recommended to set a
+ // prefix. The Redis keys otherwise are simply the username
+ // given to RiveScript.
+ prefix: "rivescript/"
+ })
+});
+
+// And carry on as normal. All user variables will be actively persisted
+// in Redis (no need to call `getUservars()` and `setUservars()` to manage
+// them yourself -- though these functions DO work and will get you current
+// data from your Redis cache!)
+```
+
+## License
+
+MIT.
diff --git a/package.json b/package.json
index b9905ae..e9c36de 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "rivescript",
- "version": "2.0.0-beta.1",
+ "version": "2.0.0",
"description": "RiveScript is a scripting language for chatterbots, making it easy to write trigger/response pairs for building up a bot's intelligence.",
"keywords": [
"bot",
diff --git a/src/rivescript.js b/src/rivescript.js
index 00d0d0c..2a1e4c1 100644
--- a/src/rivescript.js
+++ b/src/rivescript.js
@@ -22,7 +22,7 @@ near future.
*/
// Constants
-const VERSION = "2.0.0-beta.1";
+const VERSION = "2.0.0";
// Helper modules
const Parser = require("./parser");
diff --git a/webpack.config.js b/webpack.config.js
index b8bc7cc..09b99cb 100644
--- a/webpack.config.js
+++ b/webpack.config.js
@@ -18,5 +18,6 @@ module.exports = {
node: {
fs: "empty"
},
- target: "web"
+ target: "web",
+ mode: "development",
}