### Clone and Install Dependencies Source: https://github.com/photon-hq/spectrum-ts/blob/main/CONTRIBUTING.md Initial setup commands to clone the repository and install required dependencies using Bun. ```bash git clone https://github.com/photon-hq/spectrum-ts.git cd spectrum-ts bun install ``` -------------------------------- ### Run Basic Example Source: https://github.com/photon-hq/spectrum-ts/blob/main/CONTRIBUTING.md Command to execute the basic example script. ```bash bun run examples/basic/index.ts ``` -------------------------------- ### Install @spectrum-ts/hono Source: https://github.com/photon-hq/spectrum-ts/blob/main/packages/hono/README.md Install the necessary packages using bun. ```sh bun add spectrum-ts @spectrum-ts/hono hono ``` -------------------------------- ### Install @spectrum-ts/fastify Source: https://github.com/photon-hq/spectrum-ts/blob/main/packages/fastify/README.md Install the required dependencies using bun. ```sh bun add spectrum-ts @spectrum-ts/fastify fastify ``` -------------------------------- ### Install WhatsApp Business Provider Source: https://github.com/photon-hq/spectrum-ts/blob/main/packages/whatsapp-business/README.md Use this command to install the necessary packages via bun. ```sh bun add spectrum-ts @spectrum-ts/whatsapp-business ``` -------------------------------- ### Install @spectrum-ts/express Source: https://github.com/photon-hq/spectrum-ts/blob/main/packages/express/README.md Install the required packages using bun. ```sh bun add spectrum-ts @spectrum-ts/express express ``` -------------------------------- ### Install Spectrum SDK Source: https://github.com/photon-hq/spectrum-ts/blob/main/README.md Use the Bun package manager to install the batteries-included Spectrum SDK. ```bash bun add spectrum-ts ``` -------------------------------- ### Spectrum Initialization Example Source: https://github.com/photon-hq/spectrum-ts/blob/main/_autodocs/api-reference/spectrum.md Demonstrates initializing a Spectrum instance with specific options. ```typescript const app = await Spectrum({ projectId: "proj_123", projectSecret: "secret_xyz", platforms: [telegram.config()], options: { flattenGroups: true, logLevel: "warn", }, }); ``` -------------------------------- ### Install @spectrum-ts/terminal Source: https://github.com/photon-hq/spectrum-ts/blob/main/packages/terminal/README.md Install the package using the bun package manager. ```sh bun add spectrum-ts @spectrum-ts/terminal ``` -------------------------------- ### Install @spectrum-ts/slack Source: https://github.com/photon-hq/spectrum-ts/blob/main/packages/slack/README.md Use this command to add the necessary packages to your project using bun. ```sh bun add spectrum-ts @spectrum-ts/slack ``` -------------------------------- ### Install lean spectrum-ts packages Source: https://github.com/photon-hq/spectrum-ts/blob/main/packages/spectrum-ts/README.md Install only the core runtime and specific provider packages to reduce bundle size. ```sh bun add @spectrum-ts/core @spectrum-ts/imessage ``` -------------------------------- ### Install iMessage provider Source: https://github.com/photon-hq/spectrum-ts/blob/main/packages/imessage/README.md Install the core spectrum-ts package and the iMessage provider using bun. ```sh bun add spectrum-ts @spectrum-ts/imessage ``` -------------------------------- ### Install iMessage local provider Source: https://github.com/photon-hq/spectrum-ts/blob/main/packages/imessage-local/README.md Use this command to add the necessary packages to your project. ```sh bun add spectrum-ts @spectrum-ts/imessage-local ``` -------------------------------- ### Install spectrum-ts and Elysia dependencies Source: https://github.com/photon-hq/spectrum-ts/blob/main/packages/elysia/README.md Use the Bun package manager to install the required spectrum-ts and Elysia packages. ```sh bun add spectrum-ts @spectrum-ts/elysia elysia ``` -------------------------------- ### Install @spectrum-ts/telegram Source: https://github.com/photon-hq/spectrum-ts/blob/main/packages/telegram/README.md Use the bun package manager to install the core spectrum-ts library and the Telegram provider. ```sh bun add spectrum-ts @spectrum-ts/telegram ``` -------------------------------- ### Initialize minimal local setup Source: https://github.com/photon-hq/spectrum-ts/blob/main/_autodocs/api-reference/configuration.md Use this configuration for local development and testing with the terminal provider. ```typescript import { Spectrum } from "spectrum-ts"; import { terminal } from "spectrum-ts/providers/terminal"; const app = await Spectrum({ platforms: [terminal.config()], }); for await (const [space, message] of app.messages) { console.log("Received:", message.content); await space.send(text("Echo: " + message.content.text)); } ``` -------------------------------- ### Conventional Commit Example Source: https://github.com/photon-hq/spectrum-ts/blob/main/CONTRIBUTING.md Example of a commit message following the Conventional Commits specification. ```text feat: add reply support to WhatsApp provider ``` -------------------------------- ### Run Development Watch Mode Source: https://github.com/photon-hq/spectrum-ts/blob/main/CONTRIBUTING.md Command to start the project in development watch mode. ```bash bun run dev ``` -------------------------------- ### Install local iMessage provider Source: https://github.com/photon-hq/spectrum-ts/blob/main/packages/imessage/README.md Install the separate package for direct access to the local macOS Messages database. ```sh bun add @spectrum-ts/imessage-local ``` -------------------------------- ### Project Directory Structure Source: https://github.com/photon-hq/spectrum-ts/blob/main/CONTRIBUTING.md Overview of the repository layout including core packages, providers, and example applications. ```text packages/ core/ # @spectrum-ts/core - the runtime: content, platform, fusor, utils spectrum-ts/ # spectrum-ts metapackage (batteries: re-exports core + every provider) imessage/ # @spectrum-ts/imessage telegram/ # @spectrum-ts/telegram slack/ # @spectrum-ts/slack whatsapp-business/ # @spectrum-ts/whatsapp-business terminal/ # @spectrum-ts/terminal test-support/ # Shared test fixtures/helpers (private, never published) examples/ # Example apps ``` -------------------------------- ### Implement FusorClient Source: https://github.com/photon-hq/spectrum-ts/blob/main/_autodocs/platform-authoring.md Example implementation of a client factory that verifies signatures and returns parsed payloads. ```typescript function createFusorClient(): FusorClient { return { platform: "my_platform", verify: (req) => { // Verify the signature and return the parsed payload return verifySignature(req.rawBody, req.headers); }, }; } ``` -------------------------------- ### Configure cloud setup with multiple platforms Source: https://github.com/photon-hq/spectrum-ts/blob/main/_autodocs/api-reference/configuration.md Use this configuration for production environments requiring multiple platform providers and cloud-based authentication. ```typescript import { Spectrum } from "spectrum-ts"; import { imessage } from "spectrum-ts/providers/imessage"; import { telegram } from "spectrum-ts/providers/telegram"; const app = await Spectrum({ projectId: process.env.SPECTRUM_PROJECT_ID, projectSecret: process.env.SPECTRUM_PROJECT_SECRET, platforms: [ imessage.config(), telegram.config({ botToken: process.env.TELEGRAM_BOT_TOKEN, }), ], options: { flattenGroups: true, logLevel: "info", }, telemetry: true, webhookSecret: process.env.SPECTRUM_WEBHOOK_SECRET, }); ``` -------------------------------- ### Implement toVCard() usage Source: https://github.com/photon-hq/spectrum-ts/blob/main/_autodocs/cloud-and-webhooks.md Example of converting a contact object into a formatted vCard string. ```typescript import { toVCard } from "spectrum-ts"; const vcard = toVCard({ name: { given: "Jane", family: "Doe" }, emails: [{ address: "jane@example.com" }], }); console.log(vcard); // BEGIN:VCARD // VERSION:3.0 // FN:Jane Doe // EMAIL:jane@example.com // END:VCARD ``` -------------------------------- ### Implement a custom platform provider Source: https://github.com/photon-hq/spectrum-ts/blob/main/_autodocs/platform-authoring.md A complete implementation example of a platform provider using definePlatform, including configuration validation, lifecycle hooks, and message streaming. ```typescript import { definePlatform } from "spectrum-ts"; import z from "zod"; const myPlatform = definePlatform({ name: "my_platform", config: z.object({ apiKey: z.string(), baseUrl: z.string().url(), }), lifecycle: { async createClient({ config, projectId, store }) { const client = new MyPlatformAPI(config.apiKey, config.baseUrl); store.set("client", client); return client; }, async destroyClient({ client }) { await client.close(); }, }, messages: async function*({ client, config, store }) { for await (const event of client.stream()) { yield { id: event.messageId, space: { id: event.chatId }, sender: { id: event.userId }, content: asText(event.text), timestamp: new Date(event.timestamp), }; } }, user: { async resolve({ client, config, input }) { const user = await client.getUser(input.userID); return { name: user.displayName, avatar: user.avatarUrl, }; }, }, space: { async create({ client, config }, params) { return { id: params.chatId }; }, params: z.object({ chatId: z.string() }), }, actions: { send: async ({ client, config }, space, content) => { const sent = await client.sendMessage(space.id, content); return { id: sent.id, timestamp: new Date() }; }, }, events: { typing: async function*({ client, config, store }) { for await (const event of client.typingEvents()) { yield { userId: event.userId, isTyping: event.isTyping }; } }, }, }); export function config() { return myPlatform.config({ apiKey: "key_123", baseUrl: "https://..." }); } ``` -------------------------------- ### Catch UnsupportedError Source: https://github.com/photon-hq/spectrum-ts/blob/main/_autodocs/cloud-and-webhooks.md Example of catching and identifying platform-specific unsupported errors. ```typescript import { UnsupportedError } from "spectrum-ts"; try { await space.add(user); } catch (error) { if (error instanceof UnsupportedError) { console.log(`This platform doesn't support: ${error.message}`); } } ``` -------------------------------- ### Process Webhook Request Source: https://github.com/photon-hq/spectrum-ts/blob/main/_autodocs/cloud-and-webhooks.md Example of constructing a request object and invoking the webhook handler. ```typescript const req = { body: Buffer.from(rawBytes), headers: { "x-spectrum-signature": "...", "x-spectrum-timestamp": "...", }, }; const response = await spectrum.webhook(req, handler); ``` -------------------------------- ### Implement fromVCard() usage Source: https://github.com/photon-hq/spectrum-ts/blob/main/_autodocs/cloud-and-webhooks.md Example of parsing a vCard string into a structured contact object. ```typescript import { fromVCard } from "spectrum-ts"; const contact = fromVCard(` BEGIN:VCARD VERSION:3.0 FN:Jane Doe EMAIL:jane@example.com TEL:+1-555-0123 END:VCARD `); console.log(contact); // { name: { given: "Jane", family: "Doe" }, emails: [...], phones: [...] } ``` -------------------------------- ### Implement broadcast() usage Source: https://github.com/photon-hq/spectrum-ts/blob/main/_autodocs/cloud-and-webhooks.md Example of creating multiple independent subscribers from a single source stream. ```typescript const broadcaster = broadcast(sourceStream); const sub1 = broadcaster.subscribe(); const sub2 = broadcaster.subscribe(); // Both iterate the same source for await (const value of sub1) { ... } for await (const value of sub2) { ... } await broadcaster.close(); ``` -------------------------------- ### Implement stream() usage Source: https://github.com/photon-hq/spectrum-ts/blob/main/_autodocs/cloud-and-webhooks.md Example of creating a stream with an interval and consuming it via an async iterator. ```typescript import { stream } from "spectrum-ts"; const myStream = stream((emit, end) => { const interval = setInterval(() => { emit("tick"); }, 1000); return async () => { clearInterval(interval); end(); }; }); for await (const tick of myStream) { console.log(tick); } await myStream.close(); ``` -------------------------------- ### Send custom content Source: https://github.com/photon-hq/spectrum-ts/blob/main/_autodocs/api-reference/content-builders.md Example of sending a custom payload for platform-specific features. ```typescript import { custom } from "spectrum-ts"; await space.send(custom("payment_request", { amount: 100, currency: "USD", description: "Invoice #123", })); ``` -------------------------------- ### Send a voice message Source: https://github.com/photon-hq/spectrum-ts/blob/main/_autodocs/api-reference/content-builders.md Example of sending a local audio file using the voice builder. ```typescript import { voice } from "spectrum-ts"; await space.send(voice("./greeting.m4a")); ``` -------------------------------- ### Implement mergeStreams() usage Source: https://github.com/photon-hq/spectrum-ts/blob/main/_autodocs/cloud-and-webhooks.md Example of merging multiple streams and iterating over the interleaved results. ```typescript const merged = mergeStreams([stream1, stream2, stream3]); for await (const value of merged) { console.log(value); } ``` -------------------------------- ### Send text content Source: https://github.com/photon-hq/spectrum-ts/blob/main/_autodocs/api-reference/content-builders.md Examples of sending static text, streaming responses from SDKs, and custom streams with extractors. ```typescript import { text } from "spectrum-ts"; // Static text await space.send(text("Hello, world!")); // Streaming from Anthropic SDK const response = await anthropic.messages.create({ model: "claude-3-5-sonnet-20241022", stream: true, max_tokens: 1024, messages: [{ role: "user", content: "Write a haiku" }], }); await space.send(text(response)); // Streaming with custom extractor const customStream = async function*() { for (let i = 0; i < 3; i++) { yield { data: `chunk ${i}` }; } }; await space.send(text(customStream(), { extract: (chunk) => chunk.data })); ``` -------------------------------- ### Handle Webhook Result Source: https://github.com/photon-hq/spectrum-ts/blob/main/_autodocs/cloud-and-webhooks.md Example of applying the webhook result to an HTTP response object. ```typescript const result = await spectrum.webhook(request, handler); res.writeHead(result.status, result.headers); res.end(result.body); ``` -------------------------------- ### Send markdown content Source: https://github.com/photon-hq/spectrum-ts/blob/main/_autodocs/api-reference/content-builders.md Usage examples for sending static markdown strings and streaming markdown responses. ```typescript import { markdown } from "spectrum-ts"; await space.send(markdown("# Title\n\n**Bold** and *italic*")); // Streaming markdown const response = await anthropic.messages.create({ model: "claude-3-5-sonnet-20241022", stream: true, max_tokens: 1024, messages: [{ role: "user", content: "Format in markdown" }], }); await space.send(markdown(response)); ``` -------------------------------- ### Implement a WebhookHandler Source: https://github.com/photon-hq/spectrum-ts/blob/main/_autodocs/cloud-and-webhooks.md Example of a handler function that processes message content and offloads long-running tasks to a queue. ```typescript const handler: WebhookHandler = async (space, message) => { if (message.content.type === "text") { // Process the message console.log(`User said: ${message.content.text}`); // Enqueue long-running work instead of awaiting it await queueJobAsync({ spaceId: space.id, messageId: message.id, }); } }; await spectrum.webhook(request, handler); ``` -------------------------------- ### Read Receipt Usage Example Source: https://github.com/photon-hq/spectrum-ts/blob/main/_autodocs/api-reference/content-builders.md Demonstrates marking a message as read using the read function or the sugar method. ```typescript import { read } from "spectrum-ts"; await space.send(read(message)); // Sugar: message.read() await message.read(); ``` -------------------------------- ### Unsend Message Usage Example Source: https://github.com/photon-hq/spectrum-ts/blob/main/_autodocs/api-reference/content-builders.md Demonstrates retracting a message using the unsend function or the sugar method. ```typescript import { unsend } from "spectrum-ts"; const msg = await space.send(text("Oops")); await space.send(unsend(msg)); // Sugar: msg.unsend() await msg.unsend(); ``` -------------------------------- ### Send a rich link Source: https://github.com/photon-hq/spectrum-ts/blob/main/_autodocs/api-reference/content-builders.md Examples of sending a rich link, either with automatic metadata fetching or explicit overrides. ```typescript import { richlink } from "spectrum-ts"; await space.send(richlink("https://example.com/article")); // With explicit metadata await space.send(richlink(new URL("https://example.com/article"), { title: "My Article", description: "A great read", image: "https://example.com/preview.jpg", })); ``` -------------------------------- ### Get Space Display Name Source: https://github.com/photon-hq/spectrum-ts/blob/main/_autodocs/api-reference/space.md Method signature and usage for reading the chat's display name. ```typescript getDisplayName(): Promise ``` ```typescript const title = await space.getDisplayName(); ``` -------------------------------- ### Define and Use Emojis Source: https://github.com/photon-hq/spectrum-ts/blob/main/_autodocs/types.md Provides a static class for emoji constants and a type for valid emoji keys, along with a usage example for reacting to messages. ```typescript export class Emoji { static readonly THUMBS_UP: "👍"; static readonly HEART: "❤️"; static readonly THINKING: "🤔"; // ... hundreds more } export type EmojiKey = keyof typeof Emoji; ``` ```typescript import { Emoji } from "spectrum-ts"; await message.react(Emoji.THUMBS_UP); ``` -------------------------------- ### Build Project Source: https://github.com/photon-hq/spectrum-ts/blob/main/CONTRIBUTING.md Command to compile the project. ```bash bun run build ``` -------------------------------- ### Initialize Spectrum with platform providers Source: https://github.com/photon-hq/spectrum-ts/blob/main/_autodocs/api-reference/configuration.md Demonstrates how to initialize the Spectrum application with specific platform configurations for iMessage and Telegram. ```typescript import { Spectrum } from "spectrum-ts"; import { imessage } from "spectrum-ts/providers/imessage"; import { telegram } from "spectrum-ts/providers/telegram"; const app = await Spectrum({ projectId: "proj_123", projectSecret: "secret_xyz", platforms: [ imessage.config(), telegram.config({ botToken: "123456789:ABCDefGHIJKlmnOPQrsTUVwxyz", }), ], }); ``` -------------------------------- ### Initialize and Run a Spectrum Agent Source: https://github.com/photon-hq/spectrum-ts/blob/main/README.md Configure the Spectrum instance with project credentials and platform providers, then iterate over incoming messages to send replies. ```typescript import { Spectrum } from "spectrum-ts"; import { imessage } from "spectrum-ts/providers/imessage"; const app = await Spectrum({ projectId: process.env.PROJECT_ID, projectSecret: process.env.PROJECT_SECRET, platforms: [imessage.config()], }); for await (const [space, message] of app.messages) { await space.responding(async () => { await message.reply("Hello from Spectrum."); }); } ``` -------------------------------- ### Initialize Spectrum with Slack Provider Source: https://github.com/photon-hq/spectrum-ts/blob/main/packages/slack/README.md Configure the Spectrum instance by providing the Slack provider with your workspace tokens. ```ts import { Spectrum } from "spectrum-ts"; import { slack } from "@spectrum-ts/slack"; const spectrum = Spectrum({ providers: [slack.config({ tokens: { T012ABCDE: "xoxb-..." } })], }); ``` -------------------------------- ### Initialize and Use Spectrum Source: https://github.com/photon-hq/spectrum-ts/blob/main/_autodocs/api-reference/spectrum.md Demonstrates initializing a Spectrum instance with a platform provider and iterating over incoming messages to send replies. ```typescript import { Spectrum } from "spectrum-ts"; import { imessage } from "spectrum-ts/providers/imessage"; const app = await Spectrum({ projectId: process.env.PROJECT_ID, projectSecret: process.env.PROJECT_SECRET, platforms: [imessage.config()], }); for await (const [space, message] of app.messages) { await space.responding(async () => { const reply = await message.reply("Hello!"); }); } await app.stop(); ``` -------------------------------- ### Initialize Spectrum with metapackage Source: https://github.com/photon-hq/spectrum-ts/blob/main/packages/spectrum-ts/README.md Import the Spectrum class and providers from the main package to configure platforms. ```ts import { Spectrum } from "spectrum-ts"; import { imessage } from "spectrum-ts/providers/imessage"; const app = await Spectrum({ platforms: [imessage.config()], }); ``` -------------------------------- ### Handle SpectrumCloudError Source: https://github.com/photon-hq/spectrum-ts/blob/main/_autodocs/cloud-and-webhooks.md Example of catching and handling cloud-specific errors during API operations. ```typescript import { SpectrumCloudError } from "spectrum-ts"; try { const data = await cloud.getProject(projectId, projectSecret); } catch (error) { if (error instanceof SpectrumCloudError) { console.error(`Cloud error: ${error.reason}`); } } ``` -------------------------------- ### Initialize Spectrum with Hono Source: https://github.com/photon-hq/spectrum-ts/blob/main/packages/hono/README.md Configure the Spectrum app and route it through a Hono instance. ```ts import { Spectrum } from "spectrum-ts"; import { spectrum } from "@spectrum-ts/hono"; import { Hono } from "hono"; const app = await Spectrum({ webhookSecret: process.env.SPECTRUM_WEBHOOK_SECRET, }); const server = new Hono().route( "/", spectrum({ app, onMessage: async (space, message) => { if (message.content.type === "text") { await space.send(`echo: ${message.content.text}`); } }, }) ); ``` -------------------------------- ### Apply URL Sanitization Source: https://github.com/photon-hq/spectrum-ts/blob/main/_autodocs/platform-authoring.md Example of redacting sensitive query parameters from a URL string. ```typescript const url = "https://example.com/api?apiKey=secret_123"; log.info("api call", { url: sanitizeUrl(url) }); // → "https://example.com/api?***" ``` -------------------------------- ### Initialize Spectrum with Terminal Provider Source: https://github.com/photon-hq/spectrum-ts/blob/main/packages/terminal/README.md Import the terminal provider and include it in the Spectrum configuration. ```ts import { Spectrum } from "spectrum-ts"; import { terminal } from "@spectrum-ts/terminal"; const spectrum = Spectrum({ providers: [terminal] }); ``` -------------------------------- ### Initialize WhatsApp Business Provider Source: https://github.com/photon-hq/spectrum-ts/blob/main/packages/whatsapp-business/README.md Configure the provider within the Spectrum instance. Ensure the configuration object is passed to the whatsappBusiness.config method. ```ts import { Spectrum } from "spectrum-ts"; import { whatsappBusiness } from "@spectrum-ts/whatsapp-business"; const spectrum = Spectrum({ providers: [whatsappBusiness.config({ /* ... */ })], }); ``` -------------------------------- ### Initialize Fastify with Spectrum Source: https://github.com/photon-hq/spectrum-ts/blob/main/packages/fastify/README.md Register the spectrum plugin with a Fastify instance and define an onMessage handler. ```ts import { Spectrum } from "spectrum-ts"; import { spectrum } from "@spectrum-ts/fastify"; import Fastify from "fastify"; const app = await Spectrum({ webhookSecret: process.env.SPECTRUM_WEBHOOK_SECRET, }); const server = Fastify(); // The plugin owns its own raw-body parser in an encapsulated scope. server.register(spectrum, { app, onMessage: async (space, message) => { if (message.content.type === "text") { await space.send(`echo: ${message.content.text}`); } }, }); // Await listen so a startup failure surfaces instead of going unhandled. await server.listen({ port: 3000 }); ``` -------------------------------- ### Send a poll Source: https://github.com/photon-hq/spectrum-ts/blob/main/_autodocs/api-reference/content-builders.md Examples of sending a poll with simple string choices or objects with explicit IDs. ```typescript import { poll, option } from "spectrum-ts"; await space.send(poll("What's your preference?", [ "Option A", "Option B", "Option C", ])); // With explicit ids await space.send(poll("Vote now", [ { text: "Yes", id: "yes" }, { text: "No", id: "no" }, ])); ``` -------------------------------- ### Initialize Spectrum with Elysia Source: https://github.com/photon-hq/spectrum-ts/blob/main/packages/elysia/README.md Configure the Spectrum instance and register the webhook adapter within an Elysia application. ```ts import { Spectrum } from "spectrum-ts"; import { spectrum } from "@spectrum-ts/elysia"; import { Elysia } from "elysia"; const app = await Spectrum({ webhookSecret: process.env.SPECTRUM_WEBHOOK_SECRET, }); new Elysia() .use( spectrum({ app, onMessage: async (space, message) => { if (message.content.type === "text") { await space.send(`echo: ${message.content.text}`); } }, }) ) .listen(3000); ``` -------------------------------- ### SpectrumOptions Source: https://github.com/photon-hq/spectrum-ts/blob/main/_autodocs/api-reference/spectrum.md Configuration interface for the Spectrum SDK initialization. ```APIDOC ## SpectrumOptions ### Description Runtime behavior configuration passed to the Spectrum() constructor. ### Fields - **flattenGroups** (boolean) - Optional - When true, inbound group messages are yielded as individual [space, message] tuples. - **logLevel** ("debug" | "info" | "warn" | "error" | "silent") - Optional - Minimum severity for structured logs emitted by the SDK. ``` -------------------------------- ### Use envAwareConfig for configuration Source: https://github.com/photon-hq/spectrum-ts/blob/main/_autodocs/platform-authoring.md Demonstrates how to use envAwareConfig to allow explicit configuration or environment variable fallbacks. ```typescript const configSchema = z.object({ apiKey: envAwareConfig(z.string(), "MY_PLATFORM_API_KEY"), }); // User can pass apiKey explicitly const config1 = { apiKey: "key_123" }; // Or set process.env.MY_PLATFORM_API_KEY const config2 = {}; // falls back to env ``` -------------------------------- ### Initialize Spectrum with Express Source: https://github.com/photon-hq/spectrum-ts/blob/main/packages/express/README.md Mount the spectrum middleware before any global express.json() to ensure the plugin receives the raw body. ```ts import { Spectrum } from "spectrum-ts"; import { spectrum } from "@spectrum-ts/express"; import express from "express"; const app = await Spectrum({ webhookSecret: process.env.SPECTRUM_WEBHOOK_SECRET, }); const server = express(); // Mount before any global express.json() — the plugin needs the raw body. server.use( spectrum({ app, onMessage: async (space, message) => { if (message.content.type === "text") { await space.send(`echo: ${message.content.text}`); } }, }) ); server.listen(3000); ``` -------------------------------- ### Dispatch Events in Messages Handler Source: https://github.com/photon-hq/spectrum-ts/blob/main/_autodocs/platform-authoring.md Example of returning a message record or a custom event from a messages handler. ```typescript messages: async (ctx) => { const payload = ctx.payload as WebhookPayload; if (payload.type === "message") { return { id: payload.id, space: { id: payload.chatId }, sender: { id: payload.userId }, content: asText(payload.text), timestamp: new Date(), }; } if (payload.type === "typing") { return fusorEvent("typing", { userId: payload.userId, isTyping: payload.isTyping, }); } } ``` -------------------------------- ### SpectrumInstance Source: https://github.com/photon-hq/spectrum-ts/blob/main/_autodocs/api-reference/spectrum.md Methods and properties available on the initialized Spectrum instance. ```APIDOC ## SpectrumInstance ### Description The primary interface returned by Spectrum(). It provides message iteration, platform access, and lifecycle management. ### Methods - **messages** (AsyncIterable<[Space, Message]>) - An async iterable for receiving incoming messages. - **stop()** (Promise) - Gracefully shuts down the Spectrum instance. - **send(...)** (Promise) - Sends a message through the configured platforms. - **edit(message, newContent)** (Promise) - Updates an existing message with new content. - **responding(space, fn)** (Promise) - Executes a function within the context of a specific space. - **webhook(request, handler)** (Promise) - Handles incoming webhook requests. ``` -------------------------------- ### Initialize Spectrum SDK Source: https://github.com/photon-hq/spectrum-ts/blob/main/_autodocs/api-reference/configuration.md The factory function signature for initializing the Spectrum instance with provider configurations and optional project credentials. ```typescript export async function Spectrum( options: { projectId?: string; projectSecret?: string; platforms: PlatformProviderConfig[]; options?: SpectrumOptions; telemetry?: boolean; webhookSecret?: string; } ): Promise> ``` -------------------------------- ### envFor() Source: https://github.com/photon-hq/spectrum-ts/blob/main/_autodocs/platform-authoring.md Builds a formatted environment variable name prefixed with SPECTRUM_. ```APIDOC ## envFor(...parts) ### Description Build a `SPECTRUM__` env var name. ### Signature `export function envFor(...parts: string[]): string` ``` -------------------------------- ### Get space members Source: https://github.com/photon-hq/spectrum-ts/blob/main/_autodocs/api-reference/space.md Retrieves current participants excluding the agent. Throws UnsupportedError for platform-specific constraints. ```typescript const members = await space.getMembers(); for (const member of members) { console.log(member.id, member.name); } ``` -------------------------------- ### fromEnv() Source: https://github.com/photon-hq/spectrum-ts/blob/main/_autodocs/platform-authoring.md Creates a Zod schema that reads from an environment variable. ```APIDOC ## fromEnv(key) ### Description Create a Zod schema that reads from an environment variable. ### Signature `export function fromEnv(key: string): z.ZodType` ``` -------------------------------- ### Initialize and Use Logger Source: https://github.com/photon-hq/spectrum-ts/blob/main/_autodocs/platform-authoring.md Demonstrates creating a named logger instance and logging messages with attributes. ```typescript import { createLogger } from "@spectrum-ts/core/authoring"; const log = createLogger("spectrum.my_platform"); log.info("message sent", { messageId: "msg_123", userId: "user_456" }); log.error("send failed", { reason: "network" }, error); ``` -------------------------------- ### Implement Store in lifecycle and messages Source: https://github.com/photon-hq/spectrum-ts/blob/main/_autodocs/platform-authoring.md Demonstrates caching a client instance in the store during lifecycle creation and retrieving it within message handlers. ```typescript lifecycle: { async createClient({ config, store }) { const client = new MyClient(config); store.set("client", client); return client; }, }, messages: async function*({ client, store }) { const cachedClient = store.get("client"); // ... } ``` -------------------------------- ### cloud.getPlatforms() Source: https://github.com/photon-hq/spectrum-ts/blob/main/_autodocs/cloud-and-webhooks.md Fetches the list of platforms enabled for a specific project. ```APIDOC ## cloud.getPlatforms(projectId) ### Description Fetches the list of platforms enabled for a project. This is a best-effort diagnostic method that does not require a project secret. ### Parameters - **projectId** (string) - Required - Photon Cloud project identifier. ### Returns - **PlatformsData** (object) - A mapping of platform names to { enabled: boolean }. ### Example ```typescript const platforms = await cloud.getPlatforms("proj_123"); ``` ``` -------------------------------- ### Send Files and Attachments Source: https://github.com/photon-hq/spectrum-ts/blob/main/_autodocs/common-patterns.md Illustrates sending files from local paths, URLs, and buffers, as well as sending multiple attachments simultaneously. ```typescript import { Spectrum, attachment, text } from "spectrum-ts"; import { telegram } from "spectrum-ts/providers/telegram"; const app = await Spectrum({ platforms: [telegram.config({ botToken: process.env.TELEGRAM_BOT_TOKEN })], }); for await (const [space, message] of app.messages) { // Send from file path await space.send(attachment("./document.pdf")); // Send from URL await space.send( attachment(new URL("https://example.com/image.jpg")) ); // Send from buffer const buffer = Buffer.from("binary data..."); await space.send( attachment(buffer, { name: "data.bin", mimeType: "application/octet-stream", }) ); // Send multiple files const files = await space.send( attachment("./file1.pdf"), attachment("./file2.docx") ); } ``` -------------------------------- ### Get message by ID Source: https://github.com/photon-hq/spectrum-ts/blob/main/_autodocs/api-reference/space.md Resolves a message by its unique identifier. Returns undefined if the message is not found or the platform cannot resolve it. ```typescript const msg = await space.getMessage("msg_xyz"); if (msg) { await msg.react("👍"); } ``` -------------------------------- ### Run Test Suites Source: https://github.com/photon-hq/spectrum-ts/blob/main/CONTRIBUTING.md Commands to execute tests across different runtimes or specific packages. ```bash bun run test # whole suite under BOTH runtimes (via Turbo) bun run test:node # whole suite under Node only bun run test:bun # whole suite under the Bun runtime only ``` ```bash cd packages/core && bun run test:node # core suite (Node) cd packages/telegram && bun run test:bun # one provider (Bun runtime) bun run test:watch # watch mode (core, Node) ``` -------------------------------- ### cloud.getProject() Source: https://github.com/photon-hq/spectrum-ts/blob/main/_autodocs/cloud-and-webhooks.md Fetches metadata for a specific Spectrum Cloud project using project credentials. ```APIDOC ## cloud.getProject(projectId, projectSecret) ### Description Fetches Spectrum Cloud project metadata including identity, profile settings, platform statuses, and subscription information. ### Parameters - **projectId** (string) - Required - Photon Cloud project identifier. - **projectSecret** (string) - Required - Project secret for authentication. ### Returns - **ProjectData** (object) - Contains id, name, profile, platforms, and subscription status. ### Example ```typescript import { cloud } from "spectrum-ts"; const projectData = await cloud.getProject( "proj_123", "secret_xyz" ); ``` ``` -------------------------------- ### Edit Message Usage Example Source: https://github.com/photon-hq/spectrum-ts/blob/main/_autodocs/api-reference/content-builders.md Demonstrates updating a message using the edit function or the sugar method on the message object. ```typescript import { edit, text } from "spectrum-ts"; const msg = await space.send(text("Original")); await space.send(edit(text("Updated"), msg)); // Sugar: msg.edit(...) or space.edit(msg, ...) await msg.edit(text("Updated")); ``` -------------------------------- ### Spectrum(options) Source: https://github.com/photon-hq/spectrum-ts/blob/main/_autodocs/api-reference/spectrum.md The main factory function that initializes a Spectrum instance to connect AI agents to messaging platforms. ```APIDOC ## Spectrum(options) ### Description Initializes the Spectrum SDK instance. This function connects your AI agent to the specified messaging platforms and optionally integrates with Photon Cloud features. ### Parameters - **options.projectId** (string) - Optional - Photon Cloud project identifier. - **options.projectSecret** (string) - Optional - Photon Cloud project secret for authentication. - **options.platforms** (PlatformProviderConfig[]) - Required - Array of configured platform providers. - **options.providers** (PlatformProviderConfig[]) - Required - Alias for platforms. - **options.options** (SpectrumOptions) - Optional - Runtime behavior configuration. - **options.telemetry** (boolean) - Optional - Enable OTLP telemetry export. - **options.webhookSecret** (string) - Optional - HMAC secret for verifying native Spectrum webhooks. ### Return Value Returns a Promise resolving to a `SpectrumInstance` which provides methods for message handling, sending, and lifecycle management. ``` -------------------------------- ### buildPhotoAction() Source: https://github.com/photon-hq/spectrum-ts/blob/main/_autodocs/platform-authoring.md Helper for processing photo/image send actions including resizing and format conversion. ```APIDOC ## buildPhotoAction(input, options) ### Description Helper for photo/image send actions. Handles resizing, format conversion, etc. ### Signature `export function buildPhotoAction(input: PhotoInput, options?: { maxWidth?: number; maxHeight?: number }): Promise<{ data: Buffer; mimeType: string }>` ``` -------------------------------- ### voice(input, options?) Source: https://github.com/photon-hq/spectrum-ts/blob/main/_autodocs/api-reference/content-builders.md Creates a voice message or audio file content builder. ```APIDOC ## voice(input, options?) ### Description Sends a voice message or audio file. The input can be a file path, in-memory buffer, or an HTTP URL. ### Signature `export function voice(input: string | Buffer | URL, options?: { name?: string; mimeType?: string; }): ContentBuilder;` ### Parameters - **input** (string | Buffer | URL) - Required - File path, in-memory bytes, or HTTP URL. - **options.name** (string) - Optional - Display name. Inferred from path/URL if omitted. - **options.mimeType** (string) - Optional - MIME type (e.g., "audio/m4a"). Inferred from path/URL if possible. ### Returns `ContentBuilder` — resolves to `Voice`. ### Example ```typescript import { voice } from "spectrum-ts"; await space.send(voice("./greeting.m4a")); ``` ``` -------------------------------- ### Configure Telegram Provider Source: https://github.com/photon-hq/spectrum-ts/blob/main/packages/telegram/README.md Initialize the Spectrum instance with the telegram provider configuration using your bot token. ```ts import { Spectrum } from "spectrum-ts"; import { telegram } from "@spectrum-ts/telegram"; const spectrum = Spectrum({ providers: [telegram.config({ botToken: "..." })], }); ``` -------------------------------- ### asVoice() Source: https://github.com/photon-hq/spectrum-ts/blob/main/_autodocs/platform-authoring.md Creates voice/audio content. ```APIDOC ## asVoice(input: Object) ### Description Creates voice or audio content from provided read/stream functions. ``` -------------------------------- ### Development Workflow Commands Source: https://github.com/photon-hq/spectrum-ts/blob/main/CONTRIBUTING.md Standard commands for maintaining code quality and verifying changes before submission. ```bash bun run fix ``` ```bash bun run typecheck ``` ```bash bun run test ``` ```bash bun run build ``` -------------------------------- ### Configure iMessage provider Source: https://github.com/photon-hq/spectrum-ts/blob/main/packages/imessage/README.md Initialize the Spectrum instance with the iMessage platform configuration. ```ts import { Spectrum } from "spectrum-ts"; import { imessage } from "@spectrum-ts/imessage"; const spectrum = Spectrum({ platforms: [imessage.config()], }); ``` -------------------------------- ### Configure iMessage provider Source: https://github.com/photon-hq/spectrum-ts/blob/main/packages/imessage-local/README.md Initialize the Spectrum instance with the iMessage platform configuration. ```ts import { imessage } from "@spectrum-ts/imessage-local"; import { Spectrum } from "spectrum-ts"; const spectrum = Spectrum({ platforms: [imessage.config()], }); ``` -------------------------------- ### asContact() Source: https://github.com/photon-hq/spectrum-ts/blob/main/_autodocs/platform-authoring.md Creates a contact information object. ```APIDOC ## asContact(input: Object) ### Description Creates a contact information object containing name, emails, phones, organization, or addresses. ``` -------------------------------- ### Use fromEnv in Zod schema Source: https://github.com/photon-hq/spectrum-ts/blob/main/_autodocs/platform-authoring.md Demonstrates creating a Zod schema that pulls a value from an environment variable. ```typescript const schema = z.object({ apiKey: fromEnv("MY_API_KEY"), }); ``` -------------------------------- ### text(source, options?) Source: https://github.com/photon-hq/spectrum-ts/blob/main/_autodocs/api-reference/content-builders.md Creates a ContentBuilder for sending plain text, supporting both static strings and streaming sources from various LLM providers. ```APIDOC ## text(source, options?) ### Description Creates a ContentBuilder for sending plain text. This can be a static string or a streaming source from an LLM provider. ### Signature - `text(source: string): ContentBuilder` - `text(source: StreamTextSource, options?: TextStreamOptions): ContentBuilder` ### Parameters - **source** (string | StreamTextSource) - Required - A static text string or an async iterable/stream source. - **options.extract** ((chunk: T) => string | undefined) - Optional - Custom extractor function for unrecognized chunk shapes. ### Returns - **ContentBuilder** - Resolves to `{ type: "text", text: string }`. ### Example ```typescript import { text } from "spectrum-ts"; // Static text await space.send(text("Hello, world!")); // Streaming from Anthropic SDK const response = await anthropic.messages.create({ ... }); await space.send(text(response)); ``` ``` -------------------------------- ### Use reply function Source: https://github.com/photon-hq/spectrum-ts/blob/main/_autodocs/api-reference/content-builders.md Demonstrates both the canonical space.send approach and the sugar message.reply syntax. ```typescript import { reply, text } from "spectrum-ts"; // Canonical form: space.send(reply(...)) const replyMsg = await space.send(reply(text("I agree!"), message)); // Sugar: message.reply(...) const replyMsg2 = await message.reply(text("I agree!")); ``` -------------------------------- ### richlink(url, options?) Source: https://github.com/photon-hq/spectrum-ts/blob/main/_autodocs/api-reference/content-builders.md Creates a rich link preview content builder. ```APIDOC ## richlink(url, options?) ### Description Sends a rich link preview containing a URL, title, description, and image. Metadata is automatically fetched if not provided. ### Signature `export function richlink(url: string | URL, options?: { title?: string; description?: string; image?: string | URL; }): ContentBuilder;` ### Parameters - **url** (string | URL) - Required - The target URL. - **options.title** (string) - Optional - Link title. If omitted, fetched from page metadata. - **options.description** (string) - Optional - Link description. Fetched from metadata if omitted. - **options.image** (string | URL) - Optional - Link preview image URL. Fetched from metadata if omitted. ### Returns `ContentBuilder` — resolves to `Richlink`. ### Example ```typescript import { richlink } from "spectrum-ts"; await space.send(richlink("https://example.com/article")); // With explicit metadata await space.send(richlink(new URL("https://example.com/article"), { title: "My Article", description: "A great read", image: "https://example.com/preview.jpg", })); ``` ``` -------------------------------- ### Import lean spectrum-ts modules Source: https://github.com/photon-hq/spectrum-ts/blob/main/packages/spectrum-ts/README.md Import the Spectrum class and providers from their respective scoped packages. ```ts import { Spectrum } from "@spectrum-ts/core"; import { imessage } from "@spectrum-ts/imessage"; ``` -------------------------------- ### asRichlink() Source: https://github.com/photon-hq/spectrum-ts/blob/main/_autodocs/platform-authoring.md Creates a rich link. ```APIDOC ## asRichlink(input: Object) ### Description Creates a rich link object with a URL and optional metadata like title, description, and image. ``` -------------------------------- ### Manage Group Chat Members and Metadata Source: https://github.com/photon-hq/spectrum-ts/blob/main/_autodocs/common-patterns.md Demonstrates how to handle group commands like adding members, listing participants, renaming groups, and leaving a space. ```typescript import { Spectrum, text } from "spectrum-ts"; import { imessage } from "spectrum-ts/providers/imessage"; const app = await Spectrum({ platforms: [imessage.config()], }); for await (const [space, message] of app.messages) { if (message.content.type === "text") { const cmd = message.content.text.toLowerCase(); if (cmd.startsWith("!add ")) { const userId = cmd.slice(5); await space.add(userId); } else if (cmd === "!members") { const members = await space.getMembers(); for (const m of members) { console.log(m.name || m.id); } } else if (cmd.startsWith("!rename ")) { const title = cmd.slice(8); await space.rename(title); } else if (cmd === "!leave") { await space.leave(); } } } ``` -------------------------------- ### responding(fn) Source: https://github.com/photon-hq/spectrum-ts/blob/main/_autodocs/api-reference/space.md Displays a typing indicator while executing the provided callback function. ```APIDOC ## responding(fn) ### Description Mark the space as "responding" (typing indicator) while executing a callback. ### Parameters - **fn** (() => T | Promise) - Required - Synchronous or async function to execute. ``` -------------------------------- ### Use reaction function Source: https://github.com/photon-hq/spectrum-ts/blob/main/_autodocs/api-reference/content-builders.md Demonstrates both the canonical space.send approach and the sugar message.react syntax. ```typescript import { reaction } from "spectrum-ts"; // Canonical form const reactionMsg = await space.send(reaction("👍", message)); // Sugar: message.react(...) const reactionMsg2 = await message.react("👍"); ``` -------------------------------- ### asReply() Source: https://github.com/photon-hq/spectrum-ts/blob/main/_autodocs/platform-authoring.md Creates a reply to a message. ```APIDOC ## asReply(input: Object) ### Description Creates a reply to a target message with specified content. ``` -------------------------------- ### contact(input) Source: https://github.com/photon-hq/spectrum-ts/blob/main/_autodocs/api-reference/content-builders.md Constructs a contact information object in vCard format for sending via the space. ```APIDOC ## contact(input) ### Description Sends contact information formatted as a vCard. ### Signature `export function contact(input: ContactInput): ContentBuilder;` ### Parameters - **input.name** (ContactName) - Optional - Name object containing given and family names. - **input.emails** (ContactEmail[]) - Optional - Array of email objects with address and type. - **input.phones** (ContactPhone[]) - Optional - Array of phone objects with number and type. - **input.organization** (ContactOrg) - Optional - Organization details including name and title. - **input.addresses** (ContactAddress[]) - Optional - Array of address objects. ### Returns `ContentBuilder` — resolves to `Contact`. ### Example ```typescript import { contact } from "spectrum-ts"; await space.send(contact({ name: { given: "Jane", family: "Doe" }, emails: [{ address: "jane@example.com", type: "work" }], phones: [{ number: "+1-555-0123", type: "mobile" }], organization: { name: "Acme Corp", title: "Engineer" }, })); ``` ``` -------------------------------- ### Handle Webhooks with Express Source: https://github.com/photon-hq/spectrum-ts/blob/main/_autodocs/common-patterns.md Configures an Express server to receive and verify Spectrum Cloud webhooks. Requires raw body parsing for signature verification. ```typescript import express from "express"; import { Spectrum, text } from "spectrum-ts"; import { imessage } from "spectrum-ts/providers/imessage"; const app = express(); const spectrum = await Spectrum({ projectId: process.env.PROJECT_ID, projectSecret: process.env.PROJECT_SECRET, platforms: [imessage.config()], webhookSecret: process.env.SPECTRUM_WEBHOOK_SECRET, }); // Parse raw request body (required for signature verification) app.use(express.raw({ type: "*/*" })); app.post("/webhooks/spectrum", async (req, res) => { try { const response = await spectrum.webhook( { headers: req.headers, body: req.body, // Must be raw bytes }, // Handler is fire-and-forget, dispatched after response async (space, message) => { if (message.content.type === "text") { await space.send(text(`Echo: ${message.content.text}`)); } } ); res.status(response.status); for (const [key, value] of Object.entries(response.headers)) { res.setHeader(key, value); } res.end(response.body); } catch (error) { console.error("Webhook error:", error); res.status(500).send("Internal error"); } }); app.listen(3000, () => console.log("Listening on :3000")); ``` -------------------------------- ### Define ProjectData and Related Types Source: https://github.com/photon-hq/spectrum-ts/blob/main/_autodocs/types.md Metadata structures for Spectrum Cloud projects, including subscription and platform status. ```typescript export interface ProjectData { id: string; name: string; profile: ProjectProfile; platforms: PlatformsData; subscription: SubscriptionData; } export interface ProjectProfile { [key: string]: unknown; } export interface PlatformsData { [platform: string]: PlatformStatus; } export interface PlatformStatus { enabled: boolean; } export interface SubscriptionData { status: SubscriptionStatus; tier?: string; } export enum SubscriptionStatus { ACTIVE = "active", PAUSED = "paused", CANCELED = "canceled", } ``` -------------------------------- ### Define cloud.getPlatforms interface Source: https://github.com/photon-hq/spectrum-ts/blob/main/_autodocs/cloud-and-webhooks.md Interface definition for fetching enabled platform statuses. ```typescript export const cloud = { async getPlatforms(projectId: string): Promise } ``` -------------------------------- ### Store Interface Source: https://github.com/photon-hq/spectrum-ts/blob/main/_autodocs/platform-authoring.md The Store interface provides a per-platform in-memory key/value store for maintaining state across callbacks. ```APIDOC ## Store Interface ### Description Per-platform in-memory key/value store for maintaining state. Shared across all callbacks for a platform instance. ### Methods - **get(key: string)**: T | undefined - Retrieves a value from the store. - **set(key: string, value: unknown)**: void - Sets a value in the store. - **has(key: string)**: boolean - Checks if a key exists in the store. - **delete(key: string)**: boolean - Removes a key from the store. - **clear()**: void - Clears all entries from the store. ``` -------------------------------- ### app(appData) Source: https://github.com/photon-hq/spectrum-ts/blob/main/_autodocs/api-reference/content-builders.md Sends an app or interactive card with platform-specific layout configurations. ```APIDOC ## app(appData) ### Description Send an app or interactive card (platform-specific layout). ### Signature `export function app(appData: AppInput): ContentBuilder;` ### Parameters - **appData.id** (string) - Required - Unique identifier for the app. - **appData.name** (string) - Required - App name. - **appData.link** (string | URL) - Required - URL to the app or landing page. - **appData.layout** (AppLayout) - Required - Layout configuration (style, sections, buttons, etc.). ### Returns `ContentBuilder` — resolves to `App`. ### Example ```typescript import { app } from "spectrum-ts"; await space.send(app({ id: "booking", name: "Booking Assistant", link: "https://bookings.example.com", layout: { style: "card", sections: [...], }, })); ``` ``` -------------------------------- ### Handle Message Reactions in TypeScript Source: https://github.com/photon-hq/spectrum-ts/blob/main/_autodocs/common-patterns.md Shows how to react to messages and notes that inbound reactions appear as messages with content.type set to reaction. ```typescript import { Spectrum, text } from "spectrum-ts"; import { telegram } from "spectrum-ts/providers/telegram"; const app = await Spectrum({ platforms: [telegram.config({ botToken: process.env.TELEGRAM_BOT_TOKEN })], }); for await (const [space, message] of app.messages) { // Send a message and get its id const sent = await space.send(text("Do you like this?")); if (sent) { // React to our own message const reaction = await sent.react("👍"); console.log("Reacted with:", reaction?.content.emoji); // User reacts to our message (inbound) // Will appear as another message with content.type === "reaction" } } ``` -------------------------------- ### ensureM4a() Source: https://github.com/photon-hq/spectrum-ts/blob/main/_autodocs/platform-authoring.md Converts audio to M4A format if needed. ```APIDOC ## ensureM4a(input, options) ### Description Convert audio to M4A format if needed. Requires `ffmpeg-static` as a peer dependency. ### Signature `export function ensureM4a(input: Buffer | string | URL, options?: { timeout?: number }): Promise` ``` -------------------------------- ### asMarkdown() Source: https://github.com/photon-hq/spectrum-ts/blob/main/_autodocs/platform-authoring.md Creates a markdown content object. ```APIDOC ## asMarkdown(markdown: string) ### Description Creates a markdown content object from a provided string. ### Signature `asMarkdown(markdown: string): { type: "markdown"; markdown: string }` ``` -------------------------------- ### Create contact information with asContact Source: https://github.com/photon-hq/spectrum-ts/blob/main/_autodocs/platform-authoring.md Creates a contact object containing optional name, email, phone, organization, and address details. ```typescript export const asContact = (input: { name?: ContactName; emails?: ContactEmail[]; phones?: ContactPhone[]; organization?: ContactOrg; addresses?: ContactAddress[]; }): Contact ```