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 install
to install dependencies.
You'll need to create an .env
file containing exactly one of:
SOCIAL_PLATFORM=discord
SOCIAL_PLATFORM=slack
- Follow Discord Bot Tokens below if you haven't yet
- Put your
DISCORD_BOT_TOKEN
andDISCORD_CHANNEL
into.env
npm run start.watch
to start the Worker.- In another shell,
npm run workflow
to 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_SECRET
into.env
-
npm run start.watch
to start the Worker. -
In another shell,
npm run workflow
to 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:read
chat:write.public
chat:write
commands
pins:write
reactions:read
reactions: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
createIntegration
to provide APIs for the social platform being targeted (Discord
orSlack
) (see Platforms) - Logging Sinks: providing a
logger.sink
method 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.