Melony
HomeGitHub

Types

Complete TypeScript type definitions for melony.

Overview

melony is built with TypeScript and provides comprehensive type definitions for all components, hooks, and utilities. This ensures type safety and excellent developer experience.

Core Types

MelonyPart

Base part structure that represents individual pieces of content in a message.

type MelonyPart<TType = string, TExtra = {}> = {
  melonyId: string;
  type: TType;
  role: Role;
} & TExtra;

Properties

melonyId - Unique identifier for the part
type - Type of content (text, image, tool_call, etc.)
role - Who sent the message (user, assistant, system)
TExtra - Additional properties specific to the part type

MelonyMessage

Message container that groups related parts together.

type MelonyMessage<TPart = MelonyPart> = {
  id: string;
  role: Role;
  parts: TPart[];
  createdAt: Date;
  metadata?: Record<string, any>;
};

Properties

id - Unique identifier for the message
role - Who sent the message
parts - Array of parts in the message
createdAt - When the message was created
metadata - Optional additional data

Role

Enumeration of possible message roles.

type Role = "user" | "assistant" | "system";

Hook Types

useMelonyMessages Options

type UseMelonyMessagesOptions<TPart = MelonyPart> = {
  filter?: (part: TPart) => boolean;
  groupBy?: (message: MelonyMessage<TPart>) => string;
  sortBy?: (a: MelonyMessage<TPart>, b: MelonyMessage<TPart>) => number;
  limit?: number;
  joinTextDeltas?: boolean | JoinTextDeltasOptions;
  mapper?: (data: any) => TPart;
  validator?: (data: any) => data is TPart;
};

JoinTextDeltasOptions

type JoinTextDeltasOptions = {
  deltaType: string;
  idField: string;
  deltaField: string;
  outputType: string;
  outputField: string;
};

useMelonyPart Callback

type MelonyPartCallback<TPart = MelonyPart> = (part: TPart) => void;

Provider Types

MelonyProvider Props

type MelonyProviderProps<TPart = MelonyPart> = {
  endpoint?: string;
  headers?: Record<string, string>;
  children: React.ReactNode;
};

MelonyContext

type MelonyContext<TPart = MelonyPart> = {
  endpoint: string;
  headers?: Record<string, string>;
  messages: MelonyMessage<TPart>[];
  status: MelonyStatus;
  send: (message: string) => Promise<void>;
};

Status Types

MelonyStatus

type MelonyStatus = "idle" | "requested" | "streaming" | "error";

Status Values

"idle" - No active requests
"requested" - Request sent, waiting for response
"streaming" - Receiving streaming response
"error" - An error occurred

Custom Types

You can extend melony's types to create custom part structures:

Basic Custom Part

// Define your custom part type
type CustomPart = MelonyPart<"text" | "image" | "tool_call", {
  text?: string;
  imageUrl?: string;
  toolName?: string;
  toolArgs?: Record<string, any>;
}>;

// Use with MelonyProvider
<MelonyProvider<CustomPart> endpoint="/api/chat">
  <YourChatComponent />
</MelonyProvider>

Advanced Custom Part

// More complex custom part with additional metadata
type AdvancedPart = MelonyPart<"text" | "code" | "image" | "video", {
  // Text content
  text?: string;
  language?: string; // For code blocks
  
  // Media content
  imageUrl?: string;
  videoUrl?: string;
  
  // Metadata
  timestamp?: number;
  isStreaming?: boolean;
  isError?: boolean;
  errorMessage?: string;
  
  // Custom fields
  priority?: "low" | "medium" | "high";
  tags?: string[];
}>;

Custom Message with Metadata

// Custom message type with additional metadata
type CustomMessage = MelonyMessage<CustomPart> & {
  conversationId: string;
  userId: string;
  sessionId: string;
  priority: "low" | "medium" | "high";
  tags: string[];
  isRead: boolean;
  isArchived: boolean;
};

Utility Types

melony provides several utility types for common use cases:

TextPart

// Predefined type for text parts
type TextPart = MelonyPart<"text", {
  text: string;
}>;

ImagePart

// Predefined type for image parts
type ImagePart = MelonyPart<"image", {
  imageUrl: string;
  alt?: string;
  width?: number;
  height?: number;
}>;

ToolCallPart

// Predefined type for tool call parts
type ToolCallPart = MelonyPart<"tool_call", {
  toolName: string;
  toolArgs: Record<string, any>;
  toolResult?: any;
}>;

Type Guards

Use type guards to safely check part types at runtime:

// Type guard functions
function isTextPart(part: MelonyPart): part is TextPart {
  return part.type === "text" && "text" in part;
}

function isImagePart(part: MelonyPart): part is ImagePart {
  return part.type === "image" && "imageUrl" in part;
}

function isToolCallPart(part: MelonyPart): part is ToolCallPart {
  return part.type === "tool_call" && "toolName" in part;
}

// Usage in components
function PartRenderer({ part }: { part: MelonyPart }) {
  if (isTextPart(part)) {
    return <p>{part.text}</p>;
  }
  
  if (isImagePart(part)) {
    return <img src={part.imageUrl} alt={part.alt} />;
  }
  
  if (isToolCallPart(part)) {
    return (
      <div>
        <strong>Tool:</strong> {part.toolName}
        <pre>{JSON.stringify(part.toolArgs, null, 2)}</pre>
      </div>
    );
  }
  
  return null;
}

Generic Constraints

When creating custom types, you can use generic constraints to ensure type safety:

// Constraint to ensure part has required fields
type ValidPart = MelonyPart<string, {
  [K in string]: any;
}>;

// Constraint for specific part types
type TextOrImagePart = MelonyPart<"text" | "image", {
  text?: string;
  imageUrl?: string;
}>;

// Constraint for parts with specific role
type UserPart = MelonyPart<string, any> & {
  role: "user";
};

// Usage with constraints
function processPart<T extends ValidPart>(part: T): T {
  // Process the part
  return part;
}

Migration Types

Types to help with migration from other chat libraries:

// Migration from react-chatbot-kit
type ChatbotKitMessage = {
  id: string;
  message: string;
  type: "user" | "bot";
  timestamp: Date;
};

// Convert to melony format
function convertChatbotKitMessage(msg: ChatbotKitMessage): MelonyMessage {
  return {
    id: msg.id,
    role: msg.type === "bot" ? "assistant" : "user",
    parts: [{
      melonyId: `${msg.id}-part-0`,
      type: "text",
      role: msg.type === "bot" ? "assistant" : "user",
      text: msg.message,
    }],
    createdAt: msg.timestamp,
  };
}

// Migration from react-chat-widget
type ChatWidgetMessage = {
  id: string;
  text: string;
  sender: "user" | "bot";
  timestamp: number;
};

function convertChatWidgetMessage(msg: ChatWidgetMessage): MelonyMessage {
  return {
    id: msg.id,
    role: msg.sender === "bot" ? "assistant" : "user",
    parts: [{
      melonyId: `${msg.id}-part-0`,
      type: "text",
      role: msg.sender === "bot" ? "assistant" : "user",
      text: msg.text,
    }],
    createdAt: new Date(msg.timestamp),
  };
}

TypeScript Best Practices

Use strict TypeScript

Enable strict mode in your tsconfig.json to catch type errors at compile time.

Define types early

Define your custom types before implementing components to ensure consistency.

Use type guards

Implement type guards for runtime type checking and better error handling.

Document complex types

Add JSDoc comments to complex types to improve maintainability.