A sample temporal.io application that posts a daily Discord or Slack message for interactive choose-your-own-adventure stories. ✨
Watch Josh walkthrough the codebase in this video!
You can use this bot integrated with Discord, Slack, or (coming soon!) Twitter. Regardless of which platform integration you intend on using:
- Make sure Temporal Server is running locally (see the quick install guide).
npm installto install dependencies.
You'll need to create an .env file containing exactly one of:
SOCIAL_PLATFORM=discordSOCIAL_PLATFORM=slack
- Follow Discord Bot Tokens below if you haven't yet
- Put your
DISCORD_BOT_TOKENandDISCORD_CHANNELinto.env npm run start.watchto start the Worker.- In another shell,
npm run workflowto run the Workflow. - On your Discord application's Settings > OAuth2 > General (
https://discord.com/developers/applications/*/oauth2/general), copy the ngrok URL logged by the workflow into a Redirects URL and save - On your Discord application's Settings > OAuth2 > URL Generator (
https://discord.com/developers/applications/*/oauth2/url-generator), create and go through the flow of a URL with check the scopes:- Bots
- Add Reactions
- Create Messages
- Manage Messages
- Mention Everyone
- Guilds
- applications.commands
- Bots
- Create an app on Discord Developers > Applications with a name like
Choose Your Own Adventure Bot - Under Application > Bot (
https://discord.com/developers/applications/*/bot), click Add Bot - Enable the Message Content Intent toggle and save
- Grab the bot token from that page
-
Follow Slack Bot Tokens below if you haven't yet
-
Put your
SLACK_BOT_TOKEN,SLACK_CHANNEL, andSLACK_SIGNING_SECRETinto.env -
npm run start.watchto start the Worker. -
In another shell,
npm run workflowto run the Workflow. -
Modify your Slack app manifest to include a slash command under
features, using the ngrok URL logged by the workflow forurl:features: slash_commands: - command: /force description: "Force an adventure choice: 'random' or a number for an option." usage_hint: "1" url: https://<your-unique-address>.ngrok.io
- Create a new app using either flow on Slack API > Apps > New App
- Give it at least the following bot permissions:
channels:readchat:write.publicchat:writecommandspins:writereactions:readreactions:write
- Give it at least the following bot permissions:
- Install it on your Slack workspace
- Grab its Bot OAuth token from Settings > OAuth & Permissions (
https://api.slack.com/apps/*/oauth)
See temporal.io for general information and docs.temporal.io for developer documentation.
This project is based off the default Hello World project that is scaffolded out when you run npx @temporalio/create@latest.
The Temporal worker is set up in src/worker.ts.
It uses two common Temporal patterns:
- Dependency Injection: using the integration object created by
createIntegrationto provide APIs for the social platform being targeted (DiscordorSlack) (see Platforms) - Logging Sinks: providing a
logger.sinkmethod for the workflows to log out toconsole.log
The client in src/client.ts will ask Temporal to run two different workflows:
instructions: Posts instructions to the social platform and pins the messagerunGame: Continuously runs the game state until the game is finished
Each iteration of the game (so, daily), runGame goes through these steps:
- If the entry has no options, the game is over
- Post the current entry as a poll
- Check and remind people to vote once a day until either...
- ...a choice is made by consensus
- ...an admin forces a choice
- If the choice was forced by an admin, mention that
- Continue with that chosen next step in the game
The platformFactory function used in both workers and workflows reads from process.env to return the createIntegration and createServer methods for the social platform being targeted.
createIntegration: creates the client API used to send messages to the social platform.
For example, the Slack integration uses the Slack Bolt SDK.
createServer creates the (generally Express) server that runs locally and receives webhook events from the social platform.
Both the Discord and Slack servers use Ngrok to expose a local port on the public web, so that a /force command configured on the platform sends a message, it can signal to the workflow.