Giter VIP home page Giter VIP logo

alexa-app's Introduction

Table of Contents

alexa-app

A Node module to simplify the development of Alexa skills (applications.)

NPM Build Status Coverage Status

Stable Release

You're reading the documentation for the next release of alexa-app, which should be 5.0.0. Please see CHANGELOG and make sure to read UPGRADING when upgrading from a previous version. The current stable release is 4.2.3.

Introduction

This module parses HTTP JSON requests from the Alexa platform and builds the JSON response that consumed by an Alexa-compatible device, such as the Echo.

It provides a DSL for defining intents, convenience methods to more easily build the response, handle session objects, and add cards.

The intent schema definition and sample utterances are included in your application's definition, making it very simple to generate hundreds (or thousands!) of sample utterances with a few lines.

This module provides a way to host a standalone web service for an Alexa skill. If you're looking for a full-fledged application server or the ability to host multiple skills, check out alexa-app-server.

Features

  • simplified handling of requests and generating responses
  • support for asynchronous handlers
  • easy connection into AWS Lambda or Node.js Express, etc.
  • auto-generation of intent schema and sample utterances
  • support for session data
  • comprehensive test suite
  • TypeScript type definitions for type validation, IDE autocompletion, etc

Examples

AWS Lambda

Amazon skills that use alexa-app have a built-in handler method to handle calls from AWS Lambda. You need to make sure that the Handler is set to index.handler, which is the default value.

var alexa = require("alexa-app");
var app = new alexa.app("sample");

app.intent("number", {
    "slots": { "number": "AMAZON.NUMBER" },
    "utterances": ["say the number {-|number}"]
  },
  function(request, response) {
    var number = request.slot("number");
    response.say("You asked for the number " + number);
  }
);

// connect the alexa-app to AWS Lambda
exports.handler = app.lambda();

For backwards compatibility, or if you wish to change the Handler mapping to something other than index.handler, you can use the lambda() function.

A full lambda example is available here.

Express

var express = require("express");
var alexa = require("alexa-app");
var express_app = express();

var app = new alexa.app("sample");

app.intent("number", {
    "slots": { "number": "AMAZON.NUMBER" },
    "utterances": ["say the number {-|number}"]
  },
  function(request, response) {
    var number = request.slot("number");
    response.say("You asked for the number " + number);
  }
);

// setup the alexa app and attach it to express before anything else
app.express({ expressApp: express_app });

// now POST calls to /sample in express will be handled by the app.request() function
// GET calls will not be handled

// from here on, you can setup any other express routes or middleware as normal

The express function accepts the following parameters.

  • expressApp the express app instance to attach to
  • router the express router instance to attach to
  • endpoint the path to attach the express app or router to (e.g., passing 'mine' attaches to /mine)
  • checkCert when true, applies Alexa certificate checking (default: true)
  • debug when true, sets up the route to handle GET requests (default: false)
  • preRequest function to execute before every POST
  • postRequest function to execute after every POST

Either expressApp or router is required.

A full express example is available here.

Heroku Quickstart

Want to get started quickly with alexa-app and Heroku? Simply click the button below!

Deploy to Heroku

API

Skills define handlers for launch, intent, and session end, just like normal Alexa development. The alexa-app module provides a layer around this functionality that simplifies the interaction. Each handler gets passed a request and response object, which are custom for this module.

request

// return the type of request received (LaunchRequest, IntentRequest, SessionEndedRequest)
String request.type()

// return the value passed in for a given slot name
String request.slot("slotName")

// return the Slot object
Slot request.slots["slotName"]

// return the intent's confirmationStatus
String request.confirmationStatus

// check if the intent is confirmed
Boolean request.isConfirmed()

// return the Dialog object
Dialog request.getDialog()

// check if you can use session (read or write)
Boolean request.hasSession()

// return the session object
Session request.getSession()

// return the router object
Router request.getRouter()

// return the request context
request.context

// the raw request JSON object
request.data

response

The response JSON object is automatically built for you. All you need to do is tell it what you want to output.

// tell Alexa to say something; multiple calls to say() will be appended to each other
// all text output is treated as SSML
response.say(String phrase)

// empty the response text
response.clear()

// tell Alexa to re-prompt the user for a response, if it didn't hear anything valid
response.reprompt(String phrase)

// return a card to the user's Alexa app
// for Object definition @see https://developer.amazon.com/public/solutions/alexa/alexa-skills-kit/docs/alexa-skills-kit-interface-reference#card-object
// skill supports card(String title, String content) for backwards compat of type "Simple"
response.card(Object card)

// return a card instructing the user how to link their account to the skill
// this internally sets the card response
response.linkAccount()

// play audio stream (send AudioPlayer.Play directive) @see https://developer.amazon.com/public/solutions/alexa/alexa-skills-kit/docs/custom-audioplayer-interface-reference#play-directive
// skill supports stream(String url, String token, String expectedPreviousToken, Integer offsetInMilliseconds)
response.audioPlayerPlayStream(String playBehavior, Object stream)

// stop playing audio stream (send AudioPlayer.Stop directive)
response.audioPlayerStop()

// clear audio player queue (send AudioPlayer.ClearQueue directive)
// clearBehavior is "CLEAR_ALL" by default
response.audioPlayerClearQueue([ String clearBehavior ])

// tell Alexa whether the user's session is over; sessions end by default
// pass null or undefined to leave shouldEndSession undefined in the response, to satisfy newer API's
// you can optionally pass a reprompt message
response.shouldEndSession(boolean end [, String reprompt] )

// send the response to the Alexa device (success) immediately
// this returns a promise that you must return to continue the
// promise chain. Calling this is optional in most cases as it
// will be called automatically when the handler promise chain
// resolves, but you can call it and return its value in the
// chain to send the response immediately. You can also use it
// to send a response from `post` after failure.
async response.send()

// trigger a response failure
// the internal promise containing the response will be rejected, and should be handled by the calling environment
// instead of the Alexa response being returned, the failure message will be passed
// similar to `response.send()`, you must return the value returned from this call to continue the promise chain
// this is equivalent to calling `throw message` in handlers
// *NOTE:* this does not generate a response compatible with Alexa, so when calling it explicitly you may want to handle the response with `.error` or `.post`
async response.fail(String message)

// calls to response can be chained together
return response.say("OK").send()

Building SSML Responses

Use ssml-builder to build SSML responses.

Example using basic SSML tags:

var Speech = require('ssml-builder');

var speech = new Speech()
  .say('Hello')
  .pause('1s')
  .say('fellow Alexa developers')
  .pause('500ms')
  .say('Testing phone numbers')
  .sayAs({
    word: "+1-234-567-8900",
    interpret: "telephone"
  });

// change 'true' to 'false' if you want to include the surrounding <speak/> tag
var speechOutput = speech.ssml(true);
response.say(speechOutput);

Example using Amazon SSML specific tags:

var AmazonSpeech = require('ssml-builder/amazon_speech');

var speech = new AmazonSpeech()
  .say('Hello')
  .pause('1s')
  .whisper('I can see you when you are sleeping')
  .pause('500ms')
  .say('Is your phone number still')
  .sayAs({
    word: "+1-234-567-8900",
    interpret: "telephone"
  });

var speechOutput = speech.ssml();
response.say(speechOutput);

Example using multiple reprompts. The reprompts are spoken to the user if they do not respond to the main prompt or say something that does not map to a defined intent:

response.say('What is your request?')
  .reprompt('Sorry, I didn\'t catch that.')
  .reprompt('What is your request?');

session

// check if you can use session (read or write)
Boolean request.hasSession()

// get the session object
var session = request.getSession()

// set a session variable
// by defailt, Alexa only persists session variables to the next request
// the alexa-app module makes session variables persist across multiple requests
// Note that you *must* use `.set` or `.clear` to update
// session properties. Updating properties of `attributeValue`
// that are objects will not persist until `.set` is called
session.set(String attributeName, String attributeValue)

// return the value of a session variable
String session.get(String attributeName)

// session details, as passed by Amazon in the request
// for Object definition @see https://developer.amazon.com/public/solutions/alexa/alexa-skills-kit/docs/alexa-skills-kit-interface-reference#session-object
session.details = { ... }

router

// get router object
// every method of the router returns a promise, so you can chain them or just return it back to alexa-app
var router = request.getRouter()

// route request to 'MySuperIntent' intent handler
Promise router.intent('MySuperIntent')

// route request to Launch handler
Promise router.launch()

// route request to session ended handler
Promise router.sessionEnded()

// route request to audio player handler
Promise router.audioPlayer('PlaybackNearlyFinished')

// route request to playback controller handler
Promise router.playbackController('NextCommandIssued')

// route request to display element selected handler
Promise router.displayElementSelected()

// route request to custom handler
Promise router.custom('CrazyCustomEvent')

slot

// get the slot object
var slot = request.slots["slotName"]

// return the slot's name
String slot.name

// return the slot's value
String slot.value

// return the slot's confirmationStatus
String slot.confirmationStatus

// return the slot's resolutions
SlotResolution[] slot.resolutions

// check if the slot is confirmed
Boolean slot.isConfirmed()

// return the n-th resolution
SlotResolution slot.resolution(Integer n)

slotResolution

// get the resolution status code
String resolution.status

// get the list of resolution values
ResolutionValue resolution.values

// check if the resolution is matched
Boolean resolution.isMatched()

// Get the first resolution value
ResolutionValue resolution.first()

resolutionValue

// get the value name
String resolutionValue.name

// get the value id
String resolutionValue.id

Request Handlers

Your app can define a single handler for the Launch event and the SessionEnded event, and multiple intent handlers.

For switching intents, redirecting from one handler to other and other routing tasks you can use router.

LaunchRequest

app.launch(function(request, response) {
  response.say("Hello World");
  response.card("Hello World", "This is an example card");
});

IntentRequest

Define the handler for multiple intents using multiple calls to intent(). Additional Intent configuration schema like slots and sample utterances can also be passed to intent(), which is detailed below. Intent handlers that don't return an immediate response (because they do some asynchronous operation) must return a Promise. The response will be sent when the promise is resolved and fail when the promise is rejected. See example further below.

app.intent("live", {
    "dialog": {
      type: "delegate",
    },
    "slots": {
      "city": "AMAZON.US_CITY"
    },
    "utterances": [
      "in {-|city}"
    ]
  },
  function(request, response) {
    response.say("You live in " + request.slot("city"));
  }
);

app.intent("vacation", function(request, response) {
  response.say("You're now on vacation.");
});

AMAZON Specific Intents

Amazon has specific intents that have to do with basic functionality of your skill that you must add. Some examples of this are AMAZON.HelpIntent, AMAZON.StopIntent, and AMAZON.CancelIntent. Here are examples of how you would specify these types of intents.

app.intent("AMAZON.HelpIntent", {
    "slots": {},
    "utterances": []
  },
  function(request, response) {
    var helpOutput = "You can say 'some statement' or ask 'some question'. You can also say stop or exit to quit.";
    var reprompt = "What would you like to do?";
    // AMAZON.HelpIntent must leave session open -> .shouldEndSession(false)
    response.say(helpOutput).reprompt(reprompt).shouldEndSession(false);
  }
);

app.intent("AMAZON.StopIntent", {
    "slots": {},
    "utterances": []
  }, function(request, response) {
    var stopOutput = "Don't You Worry. I'll be back.";
    response.say(stopOutput);
  }
);

app.intent("AMAZON.CancelIntent", {
    "slots": {},
    "utterances": []
  }, function(request, response) {
    var cancelOutput = "No problem. Request cancelled.";
    response.say(cancelOutput);
  }
);

You do not need to pass any utterances or slots into these intents. Also when specifying the name of the intent just use the exact name Amazon provides.

Display Element Selected

Define the handler for when a user selects an element displayed on alexa touch enabled device. For instance the Echo Show.

app.displayElementSelected(function(request, response) {
  // The request object selectedElementToken will be populated with the token that was registered
  // the element in the display directive. To get the token associated with the directive itself,
  // it is populated on the request.context.Display.token property.
  handleRequestForTouchEvent(request.selectedElementToken)
})

SessionEndRequest

app.sessionEnded(function(request, response) {
  // cleanup the user's server-side session
  logout(request.userId);
  // no response required
});

AudioPlayer Event Request

Define the handler for multiple events using multiple calls to audioPlayer(). You can define only one handler per event. Event handlers that don't return an immediate response (because they do some asynchronous operation) must return a Promise.

You can define handlers for the following events:

  • PlaybackStarted
  • PlaybackFinished
  • PlaybackStopped
  • PlaybackNearlyFinished
  • PlaybackFailed

Please note:

  • PlaybackStarted and PlaybackFinished accept only Stop or ClearQueue directive in response.
  • PlaybackStopped does not accept any response.
  • PlaybackNearlyFinished and PlaybackFailed accept any AudioPlayer directive in response.

Read more about AudioPlayer request types in AudioPlayer Interface Doc.

The following example will return play directive with a next audio on AudioPlayer.PlaybackNearlyFinished request.

app.audioPlayer("PlaybackNearlyFinished", function(request, response) {
  // immediate response
  var stream = {
    "url": "https://next-song-url",
    "token": "some_token",
    "expectedPreviousToken": "some_previous_token",
    "offsetInMilliseconds": 0
  };
  response.audioPlayerPlayStream("ENQUEUE", stream);
});

See an example of asynchronous response below.

app.audioPlayer("PlaybackFinished", function(request, response) {
  // async response
  return getNextSongFromDBAsync()
  .then(function(url, token) {
    var stream = {
      "url": url,
      "token": token,
      "expectedPreviousToken": "some_previous_token",
      "offsetInMilliseconds": 0
    };
    response.audioPlayerPlayStream("ENQUEUE", stream);
  });
});

PlaybackController Event Request

PlaybackController events are sent to your skill when the user interacts with player controls on a device. Define multiple handlers for various events by making multiple calls to playbackController with each event type.

You can define handlers for the following events:

  • PlayCommandIssued
  • PauseCommandIssued
  • NextCommandIssued
  • PreviousCommandIssued

Read more about PlaybackController requests in the PlaybackController Interface Reference.

The following example will send a play directive to the device when a user presses the "next" button.

app.playbackController('NextCommandIssued', (request, response) => {
  var stream = {
    "url": "https://next-song-url",
    "token": "some_token",
    "expectedPreviousToken": "some_previous_token",
    "offsetInMilliseconds": 0
  };
  response.audioPlayerPlayStream("REPLACE_ALL", stream);
});

Note that some device interactions don't always produce PlaybackController events. See the PlaybackController Interface Introduction for more details.

Other Event Request

Handle any new requests that don't have an explicit handler type available (such as new or pre-release features) using the general on() and passing the event type.

The following example will handle an imaginary request of type DeviceEngine.InputHandler as if it were added to the Alexa API.

app.on('DeviceEngine.InputHandler', (request, response, request_json) => {
  response.say("You triggered an event from device " + request_json.request.event.deviceName);
});

Note that the raw request json is sent as the 3rd parameter to make sure the handler function has access to all data in the case that the request format differs from other handler types.

Execute Code On Every Request

In addition to specific event handlers, you can define functions that will run on every request.

pre()

Executed before any event handlers. This is useful to setup new sessions, validate the applicationId, or do any other kind of validations. You can perform asynchronous functionality in pre by returning a Promise.

app.pre = function(request, response, type) {
  if (request.applicationId != "amzn1.echo-sdk-ams.app.000000-d0ed-0000-ad00-000000d00ebe") {
    // fail ungracefully
    throw "Invalid applicationId";
    // `return response.fail("Invalid applicationId")` will also work
  }
};

// Asynchronous
app.pre = function(request, response, type) {
  return db.getApplicationId().then(function(appId) {
    if (request.applicationId != appId) {
      throw new Error("Invalid applicationId");
    }
  });
};

Note that the post() method still gets called, even if the pre() function calls send() or fail(). The post method can always override anything done before it.

post()

The last thing executed for every request. It is even called if there is an exception or if a response has already been sent. The post() function can change anything about the response. It can even turn a return response.fail() into a return respond.send() with entirely new content. If post() is called after an exception is thrown, the exception itself will be the 4th argument.

You can perform asynchronous functionality in pre by returning a Promise similar to pre or any of the handlers.

app.post = function(request, response, type, exception) {
  if (exception) {
    // always turn an exception into a successful response
    return response.clear().say("An error occured: " + exception).send();
  }
};

Schema and Utterances

The alexa-app module makes it easy to define your intent schema and generate many sample utterances. Optionally pass your schema definition along with your intent handler, and extract the generated content using either the schemas.intent() and utterances() functions on your app (if using the normal Developer portal), schemas.skillBuilder() if using the new Skill Builder beta, or schemas.askcli() if using the ask-cli tool.

Schema Syntax

Pass an object with two properties: slots and utterances.

app.intent("sampleIntent", {
    "slots": {
      "NAME": "AMAZON.US_FIRST_NAME",
      "AGE": "AMAZON.NUMBER"
    },
    "utterances": [
      "my {name is|name's} {NAME} and {I am|I'm} {-|AGE}{ years old|}"
    ]
  },
  function(request, response) { ... }
);

slots

The slots object is a simple name: type mapping. The type must be one of Amazon's built-in slot types, such as AMAZON.DATE or AMAZON.NUMBER.

custom slot types

Custom slot types are supported via the following syntax.

app.intent("sampleIntent", {
    "slots": {
      "CustomSlotName": "CustomSlotType"
    },
    "utterances": [
      "airport {information|status} for {-|CustomSlotName}"
    ]
  },
  function(request, response) { ... }
);

This will result in the following utterance list.

sampleIntent     airport information for {CustomSlotName}
sampleIntent     airport status for {CustomSlotName}

Note that the "CustomSlotType" type values must be specified in the Skill Interface's Interaction Model for the custom slot type to function correctly.

custom slot type values

If you have custom slot types, you can define your custom slot type values as well. Custom values can either be simple strings, or more full-fledged objects if you want to take advantage of Skill Builder features like synonyms. If using synonyms, you can also take advantage of utterance expansion from alexa-utterances (including dictionary), as described below.

testApp.customSlot("animal", ["cat", "dog"]);

OR

testApp.customSlot("animal", [{
  value: "dog",
  id: "canine",
  synonyms: ["doggo", "pup{per|}", "woofmeister"]
}]);

utterances

The utterances syntax allows you to generate many (hundreds or even thousands) of sample utterances using just a few samples that get auto-expanded. Any number of sample utterances may be passed in the utterances array.

This module internally uses alexa-utterances to expand these convenient strings into a format that alexa understands. Read the documentation there for a thorough set of examples on how to use this.

Using a Dictionary

Several intents may use the same list of possible values, so you want to define them in one place, not in each intent schema. Use the app's dictionary.

app.dictionary = {"colors":["red","green","blue"]};
...
"my favorite color is {colors|FAVEORITE_COLOR}"
"I like {colors|COLOR}"

Generating Schema and Utterances Output

Intent Schema Syntax

If you are using the normal Amazon developer portal, the schemas.intent() and utterances() functions will generate an intent schema JSON string and a list of utterances, respectively.

See example/express.js for one way to output this data.

// returns a String representation of an Intent Schema JSON object
app.schemas.intent() =>

{
  "intents": [{
    "intent": "MyColorIsIntent",
    "slots": [{
      "name": "Color",
      "type": "AMAZON.Color"
    }]
  }]
}

app.utterances() =>

MyColorIsIntent  my color is {dark brown|Color}
MyColorIsIntent  my color is {green|Color}
MyColorIsIntent  my favorite color is {red|Color}
MyColorIsIntent  my favorite color is {navy blue|Color}
WhatsMyColorIntent whats my color
WhatsMyColorIntent what is my color
WhatsMyColorIntent say my color
WhatsMyColorIntent tell me my color
WhatsMyColorIntent whats my favorite color
WhatsMyColorIntent what is my favorite color
WhatsMyColorIntent say my favorite color
WhatsMyColorIntent tell me my favorite color
WhatsMyColorIntent tell me what my favorite color is

Skill Builder Syntax

If you are using the Skill Builder Beta, the schemas.skillBuilder() function will generate a single schema JSON string that includes your intents with all of their utterances

app.schemas.skillBuilder() =>

{
  "intents": [{
    "name": "MyColorIsIntent",
    "samples": [
      "my color is {dark brown|Color}",
      "my color is {green|Color}",
      "my favorite color is {red|Color}",
      "my favorite color is {navy blue|Color}"
    ],
    "slots": [{
      "name": "Color",
      "type": "AMAZON.Color",
      "samples": []
    }]
  }],
  "types": [{
    "name": "MyCustomColor",
    "values": [{
      "id": null,
      "name": {
        "value": "aquamarine",
        "synonyms": ["aqua", "seafoam", "teal"]
      }
    }]
  }];
}

ask-cli Schema

The ask-cli tool accepts a schema in the same format as the Skill Builder, but is structured slightly differently. The schemas.askcli() function generates a JSON string suitable to be used with the ask deploy command.

This schema format requires you to specify the invocation name for your skill. You can set this for your skill by setting app.invocationName. If you need to use different invocation names for the same skill (e.g. you have both a staging and production version), the schema function itself can take in an invocation name which overwrites the app's default.

app.schemas.askcli("favorite color") =>

{
  "interactionModel": {
    "languageModel": {
      "invocationName": "favorite color"
      "intents": [{
        "name": "MyColorIsIntent",
        "samples": [
          "my color is {dark brown|Color}",
          "my color is {green|Color}",
          "my favorite color is {red|Color}",
          "my favorite color is {navy blue|Color}"
        ],
        "slots": [{
          "name": "Color",
          "type": "AMAZON.Color",
          "samples": []
        }]
      }],
      "types": [{
        "name": "MyCustomColor",
        "values": [{
          "id": null,
          "name": {
            "value": "aquamarine",
            "synonyms": ["aqua", "seafoam", "teal"]
          }
        }]
      }];
    }
  }
}

Cards

The response.card(Object card) method allows you to send Home Cards on the Alexa app, the companion app available for Fire OS, Android, iOS, and desktop web browsers.

The full specification for the card object passed to this method can be found here.

The full specification for the permission card can be found here.

Cards do not support SSML.

If you just want to display a card that presents the user to link their account call response.linkAccount() as a shortcut.

Card Examples

Display text only, aka Simple.

response.card({
  type: "Simple",
  title: "My Cool Card", // this is not required for type Simple
  content: "This is the\ncontent of my card"
});

Display text and image, aka Standard.

Make sure to read the restrictions on hosting the images. Must support CORS AND SSL cert signed by an Amazon approved certification authority.

response.card({
  type: "Standard",
  title: "My Cool Card", // this is not required for type Simple or Standard
  text: "Your ride is on the way to 123 Main Street!\nEstimated cost for this ride: $25",
  image: { // image is optional
    smallImageUrl: "https://carfu.com/resources/card-images/race-car-small.png", // required
    largeImageUrl: "https://carfu.com/resources/card-images/race-car-large.png"
  }
});

Display a card that presents the user to grant information to your skill, aka AskForPermissionsConsent.

If the request was for the country and postal code, then the permissions value in this response will be read::alexa:device:all:address:country_and_postal_code.

response.card({
  type: "AskForPermissionsConsent",
  permissions: [ "read::alexa:device:all:address" ] // full address
});

Custom Directives

The response.directive(Object directive) method allows you to set custom directive objects to devices to perform a specific device-level actions.

The full specification for the directive object passed to this method can be found here.

The alexa-app library has special handling for AudioPlayer directives, so you only need to use this method for more general custom directives.

The response.directive adds your directive object to the directives array in the response. To clear the directives from the response, call response.getDirectives().clear().

Dialog

The full specification for the dialog directives that can be used can be found here. See Custom Directives above for an example on manually sending dialog directives.

Note that skills must meet Alexa's requirements to use the Dialog directive.

The alexa-app library has special handling for enabling Alexa to handle Dialog directly. To configure alexa-app to delegate dialog to Alexa, enable the handling per-intent via the schema:

app.intent("sampleIntent", {
    "dialog": {
      type: "delegate"
    },
    "slots": { ... },
    "utterances": [ ... ],
  },
  function(request, response) { ... }
);

dialog object

// return the Dialog object
Dialog request.getDialog()

// return the intent's dialogState
String dialog.dialogState

// check if the intent's dialog is STARTED
Boolean dialog.isStarted()

// check if the intent's dialog is IN_PROGRESS
Boolean dialog.isInProgress()

// check if the intent's dialog is COMPLETED
Boolean dialog.isCompleted()

Error Handling

When handler functions throw exceptions, they will trigger a rejection in the promise chain. If the response has not already been sent, .post will be triggered which will allow you to force a successful response. If post does not alter the response, then a failed response will be sent. You can use this to throw an exception to or call return response.fail("message") to force a failure, but this does not generate a response compatible with Alexa.

The .error handler method will capture any errors in the chain. The default behavior of .error is to trigger response.send if the response has not already been sent, but you can force or continue failure by returning a rejected promise or throwing inside the error handler. Returning a promise allows you to do asynchronous operations in the error handler.

Ideally, you should catch errors in your handlers and respond with an appropriate output to the user. Any exceptions can be handled by a generic error handler which you can define for your app. If you want error handling to be asynchronous, it must return a promise.

app.error = function(exception, request, response) {
  response.say("Sorry, something bad happened");
};

If you do want exceptions to bubble out to the caller (and potentially cause Express to crash, for example), you can throw the exception from the error handler.

app.error = function(exception, request, response) {
  console.error(exception);
  throw exception;
};

Echo Show Support

With the addition of custom directives and support for display elements being selected, this library fully supports the Echo Show. Note that it is up to the developer to detect if the device can handle a display directive. If a display directive is returned to a non-visual device it will throw an error. One technique is to leverage the app.post call and remove any directives if the device does not support a UI. For example:

app.post(req, res, type, exception) {
  // If the device does not support display directives then remove them from the response
  if (!system.supportsDisplay(req))) {
    res.response.response.directives = []
  }
}

Please refer to Amazon's documentation for the list of supported template markup.

Asynchronous Handlers Example

If an intent or other request handler (including pre and post, but not error) will return a response later, it must a Promise. This tells the alexa-app library not to send the response automatically.

If the Promise resolves, the response will be sent. If it is rejected, it is treated as an error.

app.intent("checkStatus", function(request, response) {
  // `getAsync` returns a Promise in this example. When
  // returning a Promise, the response is sent after it
  // resolves. If rejected, it is treated as an error.
  return http.getAsync("http://server.com/status.html").then(function (rc) {
    response.say(rc.statusText);
  });
});

If you want to respond immediately, you can use return response.send() to complete the respones. Using throw msg or return response.fail(msg) will trigger immediate failure. Note: .post is still run once after response.send() or response.fail() are called.

app.intent("checkStatus", function(request, response) {
  if (currentStatus == "bad") {
    return response.fail("bad status");
  }
  else if (currentStatus == "good") {
    response.say("good status");
    return response.send();
  }

  return http.getAsync("http://server.com/status.html").then(function (rc) {
    if (rc.body == "bad") {
      throw "bad status";
    }
    response.say("good status");
    // return `response.send` to continue the promise chain
    return response.send();
  });
});

Customizing Default Error Messages

app.messages.NO_INTENT_FOUND = "Why you called dat intent? I don't know bout dat";

See the code for default messages you can override.

Read/write session data

app.launch(function(request, response) {
  request.getSession().set("number", 42);
  response.say("Would you like to know the number?");
  response.shouldEndSession(false);
});

app.intent("tellme", function(request, response) {
  var session = request.getSession();
  response.say("The number is " + session.get("number"));
  // clear only the 'number' attribute from the session
  session.clear("number");
});

// the session variables can be entirely cleared, or cleared by key
app.intent("clear", function(request, response) {
  var session = request.getSession();
  session.clear(); // or: session.clear("key") to clear a single value
  response.say("Session cleared!");
});

By default, alexa-app will persist every request session attribute into the response. This way, any session attributes you set will be sent on every subsequent request, as is typical in most web programming environments. If you wish to disable this feature, you can do so by setting app.persistentSession to false.

var app = new alexa.app("test");
app.persistentSession = false;

Define a custom endpoint name for an app

When mapped to express, the default endpoint for each app is the name of the app. You can customize this using the second parameter to the app() method.

var app = new alexa.app("hello", "myEndpointName");

All named apps can be found in the alexa.apps object, keyed by name. The value is the app itself.

License

Copyright (c) 2016-2017 Matt Kruse

MIT License, see LICENSE for details.

alexa-app's People

Contributors

adrianba avatar ajcrites avatar beeme1mr avatar bgjehu avatar camerongraybill avatar codecutteruk avatar daanzu avatar dblock avatar fremail avatar gowiem avatar jmihalicza avatar jontg avatar joshskeen avatar jstreb avatar kielni avatar kobim avatar lazerwalker avatar matt-kruse avatar mreinstein avatar nijotz avatar orta avatar padraigkitterick avatar rickwargo avatar ryoichi-obara avatar samueljr avatar sbonami avatar tejashah88 avatar trayburn avatar tternes avatar whatspaulupto avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

alexa-app's Issues

Missing support for standard requests

As far as I can tell from code and from testing, this commit has unintentionally dropped support for standard requests. I was testing upgrading to latest in master today to try out the new AudioPlayer features and I found that none of my standard launch or intent requests would go through at all. Started debugging and found on line 155 of index.js that "this.data.context" is undefined and produces a catch error that breaks execution. The JSON structure for AudioPlayer requests includes the context attribute and as such is supported by the commit, but the original support for standard requests which include the session attribute was completely dropped. Not sure how this was overlooked, but should be fixed. I am running an alexa-app-server instance to debug locally. If there is some obvious fix to this that I overlooked than it should probably be documented, but at the least the new commit should support legacy code.

What's the utility of response.session(key, val)

I am trying to wrap my head around the idea behind turning the session attributes on the response in to a setter function rather than just neatly exposing the object.

You don't have a getter function set up, so when the user needs to read values from the attributes he can't without going in and accessing request.request.sessionAttributes anyway.

Since the setter isn't providing any utility, maybe it should be removed and the interface simplified? It seems like it's a setter for setter's sake.

Pre chained with request

If I do a check in the app.pre() and it failed, I expect it just response the error message in app.pre() and terminate the request. But turned out, it sent out response in app.pre(), and still keep running the intent request.

Any thoughts?

Unable to specify utterances without multiples

I'm trying to just start a basic application that has a simple input. If I don't provide multiple options per utterance, the utterances() function fails.

$ cat foo.js 
var alexa = require('alexa-app'),
    app = new alexa.app('foobar');

app.intent('HelloWorld',
    {
        "utterances": [
            "hello world"
        ]
    },
    function(request, response) {
        response.say("hello world");
    }
);

console.log(app.utterances());
console.log(app.schema());

$ node foo.js 

/tmp/node_modules/alexa-app/node_modules/js-combinatorics/combinatorics.js:287
        if (!arguments.length) throw new RangeError;
                                     ^
RangeError
    at cartesianProduct (/tmp/node_modules/alexa-app/node_modules/js-combinatorics/combinatorics.js:287:38)
    at generateUtterances (/tmp/node_modules/alexa-app/index.js:360:51)
    at /tmp/node_modules/alexa-app/index.js:265:17
    at Array.forEach (native)
    at utterances (/tmp/node_modules/alexa-app/index.js:264:30)
    at Object.<anonymous> (/tmp/foo.js:15:17)
    at Module._compile (module.js:456:26)
    at Object.Module._extensions..js (module.js:474:10)
    at Module.load (module.js:356:32)
    at Function.Module._load (module.js:312:12)
    at Function.Module.runMain (module.js:497:10)
    at startup (node.js:119:16)
    at node.js:935:3

response.clear() may result in incorrect outputSpeech type

Calling response.clear() completely resets the outputSpeech object on the json response. If one subsequently calls response.say('This was called after clear.'), the response json will look something like this

...
"outputSpeech": {
  "type": "PlainText",
  "text": "",
  "ssml": "<speak>This was called after clear.</speak>"
}
...

Perhaps when calling response.say(), the outputSpeech type should be checked or re-assigned.

alexa-app doesn't provide certificate validation

after going through the submission process, we've been rejected because we're not validating the request signature, as per here: https://developer.amazon.com/public/solutions/alexa/alexa-skills-kit/docs/developing-an-alexa-skill-as-a-web-service#Checking%20the%20Signature%20of%20the%20Request

I think alexa-app needs to have this logic. I googled around and couldn't find any node.js examples but there are several php and java based examples out there. This might be a good starting point: http://pastebin.com/d0W9nX60

Stop wrapping calls with global try-catch

I was banging my head against the wall trying to figure out why alexa-app wasn't seeming to call some of my Intent events correctly.

I finally figured out that alexa-app wraps the event calls in a try-catch, invisibly discarding all exceptions. This makes it hell to develop on!

Reference the users location

I have a skill that needs location based services. Ex: "Alexa, what's the nearest store to my location?"

Is there a legit intent or method to reference otherwise I was planning on using the request.connection.remoteAddress value. Does the alexa-app request object support that functionality?

How do you add a context object to the request to enable audioplayer?

With the new long form audio feature utilizing the audio player directives, how do you extend/add a context object to an intent request?

I can add the directives to the response, but the Alexa Skills Kit needs the request object to look like this:

{
"version": "string",
"session": {
"new": true,
"sessionId": "string",
"application": {
"applicationId": "string"
},
"attributes": {
"string": {}
},
"user": {
"userId": "string",
"accessToken": "string"
}
},
"context": {
"System": {
"application": {
"applicationId": "string"
},
"user": {
"userId": "string",
"accessToken": "string"
},
"device": {
"supportedInterfaces": {
"AudioPlayer": {}
}
}
},
"AudioPlayer": {
"token": "string",
"offsetInMilliseconds": 0,
"playerActivity": "string"
}
},
"request": {}
}

Can you use the app.pre() or app.post library features to add the context object seen above?

alexaApp.pre fail not working as I'd expect

So i want to do a check to see if AccountLinking is setup okay in every pre check and if it's not, return a link card to as the user to setup.

But when I do the following:

res.linkAccount();
       res.say("Looks like you need to link your account. Please open the Alexa app for setup.");
      response.fail("Account not linked");

it fails completely without sending the linkAccount card or saying my message. If I comment out response.fail it works in that i see my link card and hear my message BUT it goes onto the next step whereas I'd like to return to the user rather than passing them onto the intent.

Is this just something I'm doing wrong?

Error: function response: Handler 'handle' missing on module '_apex_index'

I am sure this is a noob problem (sorry if it is), code in https://github.com/dblock/elderfield. The code works locally just fine, including if I download it from Lambda and run locally, but once on Lambda I get this:

$ apex invoke artsy
   ⨯ Error: function response: Handler 'handle' missing on module '_apex_index'

It's something in my alexa-app, because if stub that code with an apex hello world example that works. Can't find logs or anything else that helps :(

Halp!

Increase timeout

How do I increase timeout response if there is slow internet connection?

Error when uploading alexa-app to aws lamba

Hi,

I am trying to create a basic alexa-app and upload the zip file to lambda.
I have used generator-lambda to create a basic skeleton.

This is the error I keep on getting

{
  "errorMessage": "Cannot read property 'new' of undefined",
  "errorType": "TypeError",
  "stackTrace": [
    "new alexa.request (/var/task/node_modules/alexa-app/index.js:149:29)",
    "/var/task/node_modules/alexa-app/index.js:227:21",
    "tryCatcher (/var/task/node_modules/alexa-app/node_modules/bluebird/js/main/util.js:26:23)",
    "Promise._resolveFromResolver (/var/task/node_modules/alexa-app/node_modules/bluebird/js/main/promise.js:480:31)",
    "new Promise (/var/task/node_modules/alexa-app/node_modules/bluebird/js/main/promise.js:70:37)",
    "request (/var/task/node_modules/alexa-app/index.js:226:12)",
    "handler (/var/task/node_modules/alexa-app/index.js:357:10)"
  ]
}

Allow configurable error responses

There are a few verbal responses that can come directly from the alexa-app module, that cannot be configured by the developer. I would prefer to have control over any possible verbal response that comes from my app, so either kicking off an error event that can be implemented or allowing those responses to be configured would be great!

alexa.request does not seem to get session data.

Hello,

I'm trying to get alexa-app 2.0 working, and I'm stuck at just getting the launch event to fire. The error I'm getting is below. So far I just have a basic alexa-app and on app.launch i'm just console logging a SUCCESS.

It seems that alexa.request is getting json that does NOT contain any session information.

Any ideas on what to try?

Unhandled rejection TypeError: Cannot read property 'new' of undefined
    at new alexa.request (/Users/hazlewoo/Repos/quincy-echo/node_modules/alexa-app/index.js:66:26)
    at /Users/hazlewoo/Repos/quincy-echo/node_modules/alexa-app/index.js:124:18
    at request (/Users/hazlewoo/Repos/quincy-echo/node_modules/alexa-app/index.js:123:10)
    at callbacks (/Users/hazlewoo/Repos/quincy-echo/node_modules/express/lib/router/index.js:164:37)
    at param (/Users/hazlewoo/Repos/quincy-echo/node_modules/express/lib/router/index.js:138:11)
    at pass (/Users/hazlewoo/Repos/quincy-echo/node_modules/express/lib/router/index.js:145:5)
    at Router._dispatch (/Users/hazlewoo/Repos/quincy-echo/node_modules/express/lib/router/index.js:173:5)
    at Object.router (/Users/hazlewoo/Repos/quincy-echo/node_modules/express/lib/router/index.js:33:10)
    at next (/Users/hazlewoo/Repos/quincy-echo/node_modules/express/node_modules/connect/lib/proto.js:194:15)
    at Object.staticMiddleware [as handle] (/Users/hazlewoo/Repos/quincy-echo/node_modules/express/node_modules/connect/node_modules/serve-static/index.js:67:61)
    at next (/Users/hazlewoo/Repos/quincy-echo/node_modules/express/node_modules/connect/lib/proto.js:194:15)
    at cors (/Users/hazlewoo/Repos/quincy-echo/node_modules/cors/lib/index.js:122:7)
    at /Users/hazlewoo/Repos/quincy-echo/node_modules/cors/lib/index.js:177:17

The schema generated from the number example doesn't work

app.intent('StartIntent', {
        "slots": {
            "number" : "NUMBER"
        },
        "utterances": [
            "start {1-100|number}"
        ]
    },

This generates utterances:

StartIntent	start {one|number}
StartIntent	start {two|number}
StartIntent	start {three|number}

This doesn't work in sample utterances.

Error: There was a problem with your request: Incorrect syntax: A value may not be supplied for the slot 'number'. Occurred in sample 'StartIntent	start {one|number}' on line 4. 

Async requests are not handled correctly

If an intent handler tries to launch an async request and respond to alexa when the async call completes, this doesn't work. The (empty) response is already flushed. The lib should allow for the common need of using async requests in intent requests.

move generateUtterances to its' own npm module

It seems that the generateUtterances function is very well contained and is probably useful outside of alexa-app. Would you be open to moving this to new npm module, say alexa-utterances?

I'd be happy to pull this out into its' own module if that would be accepted as a PR

whitespace

Schema generation adds extra white space when skipping an optional item. An example would be "fu {bar|} baz" will generate "fu bar baz" and "fu baz" with extra white space where it skipped bar. I am trimming that down with regex replacement but it would be best if skipped pieces of a generated string do not add white space.

Sending response with <audio> tag

Your 'to-ssml.js' function is cleansing the response text of and other tags, which prevents me from adding an tag in between speech. Is there another way to add audio, for example , to the response object?

How to use built in SSML support?

Greetings,

Sorry, but I am unclear on how SSML support works currently

The only success I've had in getting an SSML output is by doing the following

awsResponse.response.response.outputSpeech.type = 'SSML';
awsResponse.response.response.outputSpeech.ssml = awsResponse.response.response.outputSpeech.text;

And manually inserting my own 'say' tags.

Obviously this isn't the ideal way to do it, but there I'm a bit confused on how to actually get an SSML response to work.

No matter what I put in response.say currently, the response type is always 'PlainText'. I noticed that calling clear can lead to this behavior, but I never call it.

If it makes a difference, my intent and launch handlers are asynchronous

Need a way to reject requests based on criteria

One common thing that I want to do at the beginning of my Alexa apps is to validate that the request has the proper AppID.

It would be nice if there were a way to do validation on a request before it moves forward with the rest of the logic.

I could see you implementing a built-in appID validation feature, or simply provide a way for the module user to provide a validation method that has the opportunity to kill the session with a response before it moves on to the other event types.

Add NewSession event

There is a handy parameter in an Alexa request, session.new, that tells the app that this request represents a brand new session.

I would like to be able to register an event handler for when a new session is started to do certain session setup tasks. Right now the only way to do this would be to check that parameter in every intent handler plus the launch handler and call the same function in each case.

Router Add-on

I'm really happy to see there are some new maintainers breathing life into this! I find this library's design far more usable than Amazon's official library.

I started writing a router (alexa-app-router) for use in my own project Mountain Top, on GitHub and published in the Skills store.

I wanted to see if others would find use in this kind of router. I find it far more usable than intents as the main Alexa paradigm. I built it to require minimal configuration, and envision supporting route parameters and more complex use cases in future versions.

As of now, it's bolt-on ready for alexa-app and doesn't alter the core library behaviors. I plan to continue it solely as an add-on now, though if many people find it useful a link in the official README could give it some visibility. If it proves popular and would fit well in the main library, I'd be happy to donate the code, otherwise I don't think there's a big downside to keeping it separate.

Number generation

The echo expects numbers like "twenty two" but the schema generation is creating them in the format of "twenty-two". I am working around this with regex replacement.

Add a way to handle unknown Intents

From the docs, it doesn't seem like it's possible to capture an IntentRequest that doesn't match any of the registered Intents.

I think it'd be best to handle it using the same app.intent method, but with a null intent name:

app.intent(null, function(request,response) {
    // Stuff to do if we get an unknown Intent!
});

Smart Home API Integration

I may have not dug into this enough, but just curious if there are any plans for having any sort of top level provider/configurator for controlling the types skills request/responses this framework uses. I know right now this works great with custom skills, but i'd imagine in a similar way we could abstract away the request/response contract for other types of skills as they become made available by Amazon.

https://developer.amazon.com/public/solutions/alexa/alexa-skills-kit/docs/smart-home-skill-api-reference

Thoughts?

Add contexts, provide another layer of routing for intents

I've got a feature idea that I am going to implement in to my own fork of this. I'd be happy to submit it as a Pull Request if this is something you'd like!

The feature introduces the idea of "Contexts" which provide another layer of routing for intents. Basically, registered Intents can have one or more "Contexts" associated with them. When a request comes in indicating that it is in a particular context (by way of a private sessionAttribute managed by the module), the actual Intent event that fires will be the one that is for that context.

This sort of thing will be very useful in situations where many different multi-step "conversational" responses are expected. For example, there might be 5 different situations in which Alexa asks the user a yes or no question, and so that same "YesIntent" would need to behave very differently in each. Currently the way to deal with this is:

app.intent("YesIntent", function(req, res) {
  if (req.session('question' === "AreYouHappy") {
    // User answered "Yes" to "Are you happy?"
  } else if (req.session('question' === "IsItRaining") {
    // User answered "Yes" to "Is it raining?"
  } else if (req.session('question' === "HaveYouEaten") {
    // User answered "Yes" to "Have you eaten?"
  } 
}

But with my proposed implementation, it would be this, which is much easier to understand at a glance what is going on. Not to mention more modular!

app.intent({intent: 'YesIntent', context: 'AreYouHappy'}, function(req, res) {
  // User answered "Yes" to "Are you happy?"
}

app.intent({intent: 'YesIntent', context: 'IsItRaining'}, function(req, res) {
  // User answered "Yes" to "Is it raining?"
}

app.intent({intent: 'YesIntent', context: 'HaveYouEaten'}, function(req, res) {
  // User answered "Yes" to "Have you eaten?"
}

If this were implemented to have fallbacks to handle Intents not found in the specific context as well as allow lists of contexts to be specified for a single event, this could end up being very powerful and easy to use for the developer.

Anyway, I'm starting work on it, but let me know if this is something you'd like PRd here!

intent authorization

How to implement some intent to only be triggered if some previous specific intent was fired.

Question about sessions

Hello

Maybe i'm to silly but i can't get sessions to work.
I have to intents. intent1 and intent2.

If intent1 is called i like to set a session var like which = 1, so i have tried to set with response.session('which','1') or request.session('which','1')

If intent2 is now called i like to read this var so i have tried with var sess = response.session('which')
or var req = request.session('which')

I only get 'undefined' or the error 'key not found on session attributes: which [TypeError: Cannot read property 'which' of undefined]'

What i'm doing wrong?

Continued Dev?

Hey Matt - it looks like Amazon has released the ASK for audio playback. Are you planning to upgrade to accommodate and/or continue dev on this project?

is it possible to do asynchronous things in pre() ?

I want my pre() to able to make asynchronous calls before running the request. like this:

app.pre = (request, response, type) ->
  getAccessToken request.data.session.user.userId, (er, token) ->
    if er or (not token)
      response.fail 'Sorry, you must link your device first.'
    else
      # TODO: proceed to normal intent handler

Is there a way to do asynchronous things in pre?

Issue: All digits replaced with spelled-out versions

I appears that the SSML update to this app introduced an issue where alexa-app is transforming all digits (1, 2, 3) in to the spelled-out version (one, two, three).

It also makes it impossible to use the "say as digits" feature in SSML due to the digits never actually ending up in the string.

Example endpoint not found

If I don't include an express route explicitly, for example, the code below works:

app.post('/appname', function(req, res) {
    res.json({
      "version": "1.0",
      "response": {
        "shouldEndSession": true,
        "outputSpeech": {
          "type": "SSML",
          "ssml": "<speak>Hmm <break time=\"1s\"/> not sure why we misconfigured this skill</speak>"
        }
      }
    });

});

then my node app throws a "There was an error calling the remote endpoint, which returned HTTP 404 : Not Found". I'm using the example code and it doesn't set the endpoint anywhere. What am i doing wrong? (This is more of a clarification than an issue... has to be something I'm doing wrong, although I've literally copied and pasted the example code)

Consider adding a license

Hi there! This is awesome stuff. I was hoping to incorporate some of this into something I'm working on, but I noticed there wasn't a license. I was wondering if you wouldn't mind adding one to the project so that I could do that and contribute any improvements back upstream. Thanks!

Standard Card type with Images

there seems to be no attribute to the response.card() function to allow for the insertion of images. Or any card type other than "Simple"

something like this would work?

this.standardCard = function(title, content, smallImageUrl, largeImageUrl){ this.response.response.card = {"type": "Standard", "title": title, "content":SSML.cleanse(content), "image": {"smallImageUrl" smallImageUrl, "largeImageUrl": largeImageUrl} }; }
https://developer.amazon.com/public/solutions/alexa/alexa-skills-kit/docs/providing-home-cards-for-the-amazon-alexa-app

Session attributes should not automatically be copied over to the response

Right now, all session attributes that come in as the request are automatically copied by alexa-app in to the response. This is only sometimes going to be desirable, and many times absolutely undesirable behavior. At the very least this should be a feature that can be toggled, and I'd suggest making the default be off. Session attributes will often hold state data, and sending along to the next request would complicate things greatly.

I do think there would be more utility in alexa-app persisting the session attributes in a historical manner, such as in an array of previous requests.

You also have a comment saying something about Alexa not doing this automatically being a bug, but that can't be the case. The response is a JSON object you build yourself; there's no concept of Alexa having any control or insight in to how you do that. There is no response object until you make it!

using callback pattern for asynchronous code

As of right now, the only way to do asynchronous things in the intent handler is to return false and then call res.send(). Although this works and is documented in the readme, it is different from the commonly used design patter of using a callback function as the last parameter. One example would be mocha and the 'done' pattern.

Also since internally the request handler uses a promise it would be nice to be able to return a promise from the intent handler, this would also allow for another commonly used pattern of writing asynchronous code.

Thoughts?

Configuration option to turn off automatically sending a response unless the intent returns false

I'm working on a skill server written in typescript that utilizes the beauty of async/await. Trouble is, in order make async calls within my intent handlers, something integral to the application, I have to return false before the async call is made. This isn't possible (or at least I haven't figured out a reasonable work around) for me to do in the way I want to write my intents as async/await makes the flow of my program seem procedural to the author. So, instead of returning false outside of the async callback function, the remainder of the code block gets wrapped up into a callback at compile time.

I have gone into the library and switched off the check that calls res.send() should the intent not return false, but I would love to have a configuration option when creating the alexa-app that just says "autoSend: false" or something like that.

Would be happy to write it and submit a pull request. What do you think? Am I missing something? Does this seem like a reasonable feature?

Need a way to handle custom slot types

Amazon is now recommending we use custom slot types instead of the "LITERAL" type. More here:

[https://developer.amazon.com/public/solutions/alexa/alexa-skills-kit/docs/alexa-skills-kit-interaction-model-reference#Custom Slot Type Syntax](https://developer.amazon.com/public/solutions/alexa/alexa-skills-kit/docs/alexa-skills-kit-interaction-model-reference#Custom Slot Type Syntax)

Basically, in our utterances we don't put the example variables, so for example:

app.intent("whereIsIntent", {
  slots: {
    "NAME": "LIST_OF_NAMES",
  },
  utterances: [
    "where is {mom|dad|my brother|my sister|my daughter|my son|NAME}"
  ],
  function (req, res) {
    var name = request.slot("NAME");

    response.say("I don't know where " + name + "is.");
  }
});

The utterances generated should be:

whereIsIntent   where is {NAME}

And then perhaps we could use a separate method on the app, along with schema and utterances, something like customtype(slotname)? Which would output the following:

mom
dad
my brother
my sister
my daughter
my son

I still think there is value in your combinatorics stuff, and also perhaps it can be re-evaluated as it seems this is exactly what they are trying to obviate with the custom slot type feature.

.eslintrc should have extension

This is nit-picky, but the use of an extensionless eslint is deprecated, and it should be super simple to change.

v1.10.0 introduces the ability to use configuration files in different formats. Instead of the regular .eslintrc file, you can use a JavaScript (.eslintrc.js), a YAML file (.eslintrc.yml or .eslintrc.yaml), or a JSON file (.eslintrc.json). We are formally deprecating use of the .eslintrc extensionless configuration file format in favor the format-specific versions. Don't worry, we'll still support .eslintrc files for a long time, but we'd like to encourage everyone to move to the new file formats as you'll get advantages such as syntax highlighting and error detection with many editors.

(bold added by me)

utterances not keeping braces around slot names

utterances not keeping braces around slot names when generating content.
Also slots are optional, please remove if empty.

From this:

    {
        "slots": {"date": "AMAZON.DATE", "city": "AMAZON.US_CITY"},
        "utterances": [
            "what movies are playing {on |} {date}",
            "what movies are playing {in|near|around} {city}",
            "what movies are playing {in|near|around} {city} {on |} {date}",
            "what movies are playing {on |} {date} {in|near|around} {city}"
        ]
    }

Generates this:

{
   "intents": [
      {
         "intent": "AMAZON.HelpIntent",
         "slots": []
      },
      {
         "intent": "AMAZON.StopIntent",
         "slots": []
      },
      {
         "intent": "AMAZON.CancelIntent",
         "slots": []
      },
      {
         "intent": "GetMoviesIntent",
         "slots": [
            {
               "name": "date",
               "type": "AMAZON.DATE"
            },
            {
               "name": "city",
               "type": "AMAZON.US_CITY"
            }
         ]
      }
   ]
}

GetMoviesIntent what movies are playing on date
GetMoviesIntent what movies are playing date
GetMoviesIntent what movies are playing in city
GetMoviesIntent what movies are playing near city
GetMoviesIntent what movies are playing around city
GetMoviesIntent what movies are playing in city on date
GetMoviesIntent what movies are playing near city on date
GetMoviesIntent what movies are playing around city on date
GetMoviesIntent what movies are playing in city date
GetMoviesIntent what movies are playing near city date
GetMoviesIntent what movies are playing around city date
GetMoviesIntent what movies are playing on date in city
GetMoviesIntent what movies are playing date in city
GetMoviesIntent what movies are playing on date near city
GetMoviesIntent what movies are playing date near city
GetMoviesIntent what movies are playing on date around city
GetMoviesIntent what movies are playing date around city

Card subtitle deprecated?

The API for including a card has an optional subtitle argument. But it doesn't seem to do anything. Looking at this forum post, this parameter may have been removed from the Alexa Skills API? The subtitle on cards is now the skill name.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.