Skip to content

Adding State

Sup provides several ways to store and retrieve state in your patches. This guide covers the different types of state storage and when to use each one.

State Scopes

Sup offers four scopes for storing state:

  1. Chat Scope - Data tied to a specific chat room
  2. Message Scope - Data tied to specific messages
  3. User Scope - Data tied to specific users
  4. Global Scope - Data shared across all uses of this patch

Chat-Scoped State

Chat-scoped state is shared by all users within a chat. It’s perfect for collaborative features or chat-wide settings.

function main() {
// Store chat settings
sup.set("gameActive", true);
sup.set("currentRound", 1);
// Get chat state
const isGameActive = sup.get("gameActive");
const round = sup.get("currentRound");
if (isGameActive) {
return `Round ${round} is active!`;
}
}

Common Chat State Uses

// Store chat preferences
sup.set("language", "jp");
// Manage game state
function startGame() {
sup.set("gameState", {
active: true,
players: [],
scores: {},
round: 1,
});
}

Message-Scoped State

Message-scoped state lets you store data tied to the message the patch was run in.

function main() {
// Store data for current message
sup.message.set("yes", 2);
sup.message.set("no", 1);
// Get message state
const yes = sup.message.get("yes");
const no = sup.message.get("no");
}

Common Message State Uses

// Track message interactions
function onReact(e) {
const reactions = sup.message.get("reactions") || [];
reactions.push(e.reactionEmoji);
sup.message.set("reactions", reactions);
}
// Store message metadata
function markAsAnswered() {
sup.message.set("status", {
answered: true,
answeredBy: sup.user.username,
answeredAt: new Date(),
});
}
// Track thread state
function updateThread() {
sup.message.set("threadInfo", {
replyCount: 5,
lastReplyAt: new Date(),
participants: ["user1", "user2"],
});
}

User-Scoped State

User-scoped state is perfect for storing user preferences, progress, or personal data. It’s accessed through SupUser instances.

function main() {
// Store user preference
sup.user.set("color", "green");
// Get user preference
const color = sup.user.get("color");
// Store user stats
sup.user.set("gameScore", 100);
sup.user.set("lastPlayed", new Date());
}

Working with Other Users

You can also access state for other users when you have their SupUser instance:

function onReply(e) {
// Get the reply author's data
const authorStats = e.reply.author.get("stats");
// Update their interaction count
const interactions = e.reply.author.get("interactions") || 0;
e.reply.author.set("interactions", interactions + 1);
}

Global State

Global state is shared across all uses of your patch.

function main() {
// Store global data
sup.global.set("totalGames", 100);
sup.global.set("highScores", [
{ name: "player1", score: 1000 },
{ name: "player2", score: 950 },
]);
// Get global data
const games = sup.global.get("totalGames");
const scores = sup.global.get("highScores");
}

Listing Keys

Each scope supports a .keys() method that returns an array of all stored keys:

// List all chat-scoped keys
const chatKeys = sup.keys(); // or sup.chat.keys()
// List all global keys
const globalKeys = sup.global.keys();
// List all user-scoped keys
const userKeys = sup.user.keys();
// List all message-scoped keys
const msgKeys = sup.message.keys();

Keys that have been set() during the current patch run are included in the results, even before they are persisted to the database.

Complex Data Structures

All state methods support storing complex data structures:

// Store objects
sup.user.set("profile", {
preferences: {
color: "green",
number: 42,
},
achievements: ["level1", "level2"],
});
// Store arrays
sup.set("players", [
{ id: "123", name: "Player 1", ready: true },
{ id: "456", name: "Player 2", ready: false },
]);
// Store dates
sup.user.set("lastLogin", new Date());
// Store Sup objects
sup.set("lastImage", sup.image("example.jpg"));

Notes

  • State is persistent across patch runs
  • State can store any JSON-serializable data
  • Choose appropriate scope for your needs
  • Initialize state with sensible defaults, and use fallbacks when using the get method