Voxa Application

class VoxaApp(config)
Arguments:
  • config – Configuration for your skill, it should include Views and Variables and optionally a model and a list of appIds.

If appIds is present then the framework will check every alexa event and enforce the application id to match one of the specified application ids.

const app = new VoxaApp.pp({ Model, variables, views, appIds });
VoxaApp.execute(event, context)

The main entry point for the Skill execution

Arguments:
  • event – The event sent by the platform.
  • context – The context of the lambda function
Returns:

Promise: A response resolving to a javascript object to be sent as a result to Alexa.

app.execute(event, context)
  .then(result => callback(null, result))
  .catch(callback);
VoxaApp.onState(stateName, handler)

Maps a handler to a state

Arguments:
  • stateName (string) – The name of the state
  • handler (function/object) – The controller to handle the state
  • intent (string/array) – The intents that this state will handle
Returns:

An object or a promise that resolves to an object that specifies a transition to another state and/or a view to render

app.onState('entry', {
  LaunchIntent: 'launch',
  'AMAZON.HelpIntent': 'help',
});

app.onState('launch', (voxaEvent) => {
  return { tell: 'LaunchIntent.OpenResponse', to: 'die' };
});

Also you can use a shorthand version to define a controller. This is very useful when having a controller that only returns a transition

voxaApp.onState('launch',
  {
    flow: 'yield'
    reply: 'LaunchIntent.OpenResponse',
    to: 'nextState'
  }
);

You can also set the intent that the controller will handle. If set, any other triggered intent will not enter into the controller.

voxaApp.onState("agreed?", {
  to: "PurchaseAccepted"
}, "YesIntent");

voxaApp.onState("agreed?", {
  to: "TransactionCancelled"
}, ["NoIntent", "CancelIntent"]);

voxaApp.onState("agreed?", {
  to: "agreed?",
  reply: "Help.ArticleExplanation",
  flow: "yield"
}, "HelpIntent");

voxaApp.onState("agreed?", {
  to: "agreed?",
  reply: "UnknownInput",
  flow: "yield"
});

The order on how you declare your controllers matter in Voxa

You can set multiple controllers for a single state, so how do you know which code will be executed? The first one that Voxa finds. Take this example:

voxaApp.onState('ProcessUserRequest', (voxaEvent) => {
  // Some code
  return { tell: 'ThankYouResponse', to: 'die' };
});
voxaApp.onState('ProcessUserRequest', (voxaEvent) => {
  // Some other code
  return { tell: 'GoodbyeResponse', to: 'die' };
});

If the state machine goes to the ProcessUserRequest, the code running will always be the first one, so the user will always hear the ThankYouResponse.

The only scenario where this is overwritten is when you have more than one handler for the same state, and one of them has one or more intents defined. If the user triggers the intent that’s inside the list of one-controller intents, Voxa will give it priority. For example, take this code:

voxaApp.onState("agreed?", {
  to: "PurchaseAccepted"
}, "YesIntent");

voxaApp.onState("agreed?", {
  to: "agreed?",
  reply: "UnknownInput",
  flow: "yield"
});

voxaApp.onState("agreed?", {
  to: "TransactionCancelled"
}, ["NoIntent", "CancelIntent"]);

If the user triggers the NoIntent, and the state machine goes to the agreed? state, the user will listen to the TransactionCancelled response, it doesn’t matter if the controller is placed above or below a controller without defined intents, the priority will go to the controller with the defined intent.

VoxaApp.onIntent(intentName, handler)

A shortcut for definining state controllers that map directly to an intent

Arguments:
  • intentName (string) – The name of the intent
  • handler (function/object) – The controller to handle the state
Returns:

An object or a promise that resolves to an object that specifies a transition to another state and/or a view to render

app.onIntent('HelpIntent', (voxaEvent) => {
  return { tell: 'HelpIntent.HelpAboutSkill' };
});
VoxaApp.onIntentRequest(callback[, atLast])

This is executed for all IntentRequest events, default behavior is to execute the State Machine machinery, you generally don’t need to override this.

Arguments:
  • callback (function) –
  • last (bool) –
Returns:

Promise

VoxaApp.onLaunchRequest(callback[, atLast])

Adds a callback to be executed when processing a LaunchRequest, the default behavior is to fake the alexa event as an IntentRequest with a LaunchIntent and just defer to the onIntentRequest handlers. You generally don’t need to override this.

VoxaApp.onBeforeStateChanged(callback[, atLast])

This is executed before entering every state, it can be used to track state changes or make changes to the alexa event object

VoxaApp.onBeforeReplySent(callback[, atLast])

Adds a callback to be executed just before sending the reply, internally this is used to add the serialized model and next state to the session.

It can be used to alter the reply, or for example to track the final response sent to a user in analytics.

app.onBeforeReplySent((voxaEvent, reply) => {
  const rendered = reply.write();
  analytics.track(voxaEvent, rendered)
});
VoxaApp.onAfterStateChanged(callback[, atLast])

Adds callbacks to be executed on the result of a state transition, this are called after every transition and internally it’s used to render the transition reply using the views and variables

The callbacks get voxaEvent, reply and transition params, it should return the transition object

app.onAfterStateChanged((voxaEvent, reply, transition) => {
  if (transition.reply === 'LaunchIntent.PlayTodayLesson') {
    transition.reply = _.sample(['LaunchIntent.PlayTodayLesson1', 'LaunchIntent.PlayTodayLesson2']);
  }

  return transition;
});
VoxaApp.onUnhandledState(callback[, atLast])

Adds a callback to be executed when a state transition fails to generate a result, this usually happens when redirecting to a missing state or an entry call for a non configured intent, the handlers get a alexa event parameter and should return a transition the same as a state controller would.

VoxaApp.onSessionStarted(callback[, atLast])

Adds a callback to the onSessinStarted event, this executes for all events where voxaEvent.session.new === true

This can be useful to track analytics

app.onSessionStarted((voxaEvent, reply) => {
  analytics.trackSessionStarted(voxaEvent);
});
VoxaApp.onRequestStarted(callback[, atLast])

Adds a callback to be executed whenever there’s a LaunchRequest, IntentRequest or a SessionEndedRequest, this can be used to initialize your analytics or get your account linking user data. Internally it’s used to initialize the model based on the event session

app.onRequestStarted((voxaEvent, reply) => {
  let data = ... // deserialized from the platform's session
  voxaEvent.model = this.config.Model.deserialize(data, voxaEvent);
});
VoxaApp.onSessionEnded(callback[, atLast])

Adds a callback to the onSessionEnded event, this is called for every SessionEndedRequest or when the skill returns a transition to a state where isTerminal === true, normally this is a transition to the die state. You would normally use this to track analytics

VoxaApp.onSystem.ExceptionEncountered(callback[, atLast])

This handles System.ExceptionEncountered event that are sent to your skill when a response to an AudioPlayer event causes an error

return Promise.reduce(errorHandlers, (result, errorHandler) => {
  if (result) {
    return result;
  }
  return Promise.resolve(errorHandler(voxaEvent, error));
}, null);

Error handlers

You can register many error handlers to be used for the different kind of errors the application could generate. They all follow the same logic where if the first error type is not handled then the default is to be deferred to the more general error handler that ultimately just returns a default error reply.

They’re executed sequentially and will stop when the first handler returns a reply.

VoxaApp.onError(callback[, atLast])

This is the more general handler and will catch all unhandled errors in the framework, it gets (voxaEvent, error) parameters as arguments

app.onError((voxaEvent, error) => {
  return new Reply(voxaEvent, { tell: 'An unrecoverable error occurred.' })
    .write();
});

Playback Controller handlers

Handle events from the AudioPlayer interface

audioPlayerCallback(voxaEvent, reply)

All audio player middleware callbacks get a alexa event and a reply object

Arguments:
  • voxaEvent (AlexaEvent) – The alexa event sent by Alexa
  • reply (object) – A reply to be sent as a response
Returns object write:
 

Your alexa event handler should return an appropriate response according to the event type, this generally means appending to the reply object

In the following example the alexa event handler returns a REPLACE_ENQUEUED directive to a PlaybackNearlyFinished() event.

app['onAudioPlayer.PlaybackNearlyFinished']((voxaEvent, reply) => {
  const playAudio = new PlayAudio({
    behavior: "REPLACE_ALL",
    offsetInMilliseconds: 0,
    token: "",
    url: 'https://www.dl-sounds.com/wp-content/uploads/edd/2016/09/Classical-Bed3-preview.mp3'
  });

  playAudio.writeToReply(reply);

  return reply;
});
VoxaApp.onAudioPlayer.PlaybackStarted(callback[, atLast])
VoxaApp.onAudioPlayer.PlaybackFinished(callback[, atLast])
VoxaApp.onAudioPlayer.PlaybackStopped(callback[, atLast])
VoxaApp.onAudioPlayer.PlaybackFailed(callback[, atLast])
VoxaApp.onAudioPlayer.PlaybackNearlyFinished(callback[, atLast])
VoxaApp.onPlaybackController.NextCommandIssued(callback[, atLast])
VoxaApp.onPlaybackController.PauseCommandIssued(callback[, atLast])
VoxaApp.onPlaybackController.PlayCommandIssued(callback[, atLast])
VoxaApp.onPlaybackController.PreviousCommandIssued(callback[, atLast])

Alexa Skill Event handlers

Handle request for the Alexa Skill Events

alexaSkillEventCallback(alexaEvent)

All the alexa skill event callbacks get a alexa event and a reply object

Arguments:
  • alexaEvent (AlexaEvent) – The alexa event sent by Alexa
  • reply (object) – A reply to be sent as the response
Returns object reply:
 

Alexa only needs an acknowledgement that you received and processed the event so it doesn’t need to resend the event. Just returning the reply object is enough

This is an example on how your skill can process a SkillEnabled() event.

app['onAlexaSkillEvent.SkillEnabled']((alexaEvent, reply) => {
  const userId = alexaEvent.user.userId;
  console.log(`skill was enabled for user: ${userId}`);
  return reply;
});
VoxaApp.onAlexaSkillEvent.SkillAccountLinked(callback[, atLast])
VoxaApp.onAlexaSkillEvent.SkillEnabled(callback[, atLast])
VoxaApp.onAlexaSkillEvent.SkillDisabled(callback[, atLast])
VoxaApp.onAlexaSkillEvent.SkillPermissionAccepted(callback[, atLast])
VoxaApp.onAlexaSkillEvent.SkillPermissionChanged(callback[, atLast])

Alexa List Event handlers

Handle request for the Alexa List Events

alexaListEventCallback(alexaEvent)

All the alexa list event callbacks get a alexa event and a reply object

Arguments:
  • alexaEvent (AlexaEvent) – The alexa event sent by Alexa
  • reply (object) – A reply to be sent as the response
Returns object reply:
 

Alexa only needs an acknowledgement that you received and processed the event so it doesn’t need to resend the event. Just returning the reply object is enough

This is an example on how your skill can process a ItemsCreated() event.

app['onAlexaHouseholdListEvent.ItemsCreated']((alexaEvent, reply) => {
  const listId = alexaEvent.request.body.listId;
  const userId = alexaEvent.user.userId;
  console.log(`Items created for list: ${listId}` for user ${userId});
  return reply;
});
VoxaApp.onAlexaHouseholdListEvent.ItemsCreated(callback[, atLast])
VoxaApp.onAlexaHouseholdListEvent.ItemsUpdated(callback[, atLast])
VoxaApp.onAlexaHouseholdListEvent.ItemsDeleted(callback[, atLast])