Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.photon.codes/docs/llms.txt

Use this file to discover all available pages before exploring further.

A space is a conversation — a DM, a group chat, a terminal session. A user is a participant identified by a platform-specific ID. Both carry a __platform tag so the narrowing functions from platform narrowing can recover their platform-specific shapes.

Space

Every exposes the same interface regardless of platform:
MethodDescription
send(...content)Send one or more content items into the conversation.
startTyping()Show a typing indicator. No-op if the platform doesn’t support it.
stopTyping()Hide the typing indicator.
responding(fn)Start a typing indicator, run fn, and stop the indicator when it completes — even if fn throws.
for await (const [space, message] of app.messages) {
  await space.send("Got it.");
}

User

Users are minimal: an ID and a platform tag.
interface User {
  readonly id: string;
  readonly __platform: string;
}
Resolve a user from a platform-specific identifier through a narrowed platform instance:
import { imessage } from "spectrum-ts/providers/imessage";

const im = imessage(app);
const alice = await im.user("+15551234567");
The returned user may include additional platform-specific fields when the provider defines a user.schema.

Typing indicators

Manual

await space.startTyping();
// ... do work ...
await space.stopTyping();
These are sugar for space.send(typing("start")) and space.send(typing("stop")) — see Content for the canonical form.

Automatic with responding

responding is the recommended pattern. It guarantees the typing indicator is cleared even if the inner function throws:
await space.responding(async () => {
  const result = await generateResponse(message);
  await space.send(result);
});
The helper is also available on the app itself:
await app.responding(space, async () => {
  await space.send("Thinking...");
});

Creating a space

To start a new conversation, use platform narrowing to get a platform instance, then pass the users:
const im = imessage(app);
const alice = await im.user("+15551111111");
const bob = await im.user("+15552222222");

// DM
const dm = await im.space(alice);

// Group
const group = await im.space(alice, bob);

await group.send("Welcome to the group.");
The returned space is the platform-specific type — so you can read extra fields like type: "dm" | "group" on iMessage — but it also satisfies the generic Space interface, so send(), startTyping(), and friends are always available.