@cloudillo/types

Overview

TypeScript type definitions for Cloudillo with runtime validation using @symbion/runtype.

Installation

pnpm add @cloudillo/types

Core Types

Profile

User or community profile information.

import type { Profile } from '@cloudillo/types'

const profile: Profile = {
  idTag: 'alice@example.com',
  name: 'Alice Johnson',
  profilePic: '/file/b1~abc123'
}

Fields:

  • idTag: string - Unique identity (DNS-based)
  • name?: string - Display name
  • profilePic?: string - Profile picture URL

Action

Represents a social action or activity.

import type { Action } from '@cloudillo/types'

const action: Action = {
  actionId: 'act_123',
  type: 'POST',
  issuerTag: 'alice@example.com',
  content: {
    text: 'Hello, world!',
    title: 'My First Post'
  },
  createdAt: 1735000000,
  status: 'A'
}

Fields:

  • actionId: string - Unique action identifier
  • type: ActionType - Type of action (POST, CMNT, REACT, etc.)
  • issuerTag: string - Who created the action
  • content?: unknown - Action-specific content
  • createdAt: number - Unix timestamp (seconds)
  • status?: ActionStatus - P/A/D/C/N
  • subType?: string - Action subtype/category
  • parentId?: string - Parent action (for threads)
  • rootId?: string - Root action (for deep threads)
  • audienceTag?: string - Target audience
  • subject?: string - Subject/target (e.g., who to follow)
  • attachments?: string[] - File IDs
  • expiresAt?: number - Expiration timestamp

ActionType

Literal union of all action types.

import type { ActionType } from '@cloudillo/types'

const type: ActionType =
  | 'CONN'   // Connection request
  | 'FLLW'   // Follow user
  | 'POST'   // Create post
  | 'REPOST' // Repost/share
  | 'REACT'  // Reaction
  | 'CMNT'   // Comment
  | 'SHRE'   // Share resource
  | 'MSG'    // Message
  | 'FSHR'   // File share
Additional Action Types

ACK (Acknowledgment) and RSTAT (Reaction Statistics) exist as action variants in the tagged union (tBaseAction) but are not part of the ActionType literal type. They are used internally for specific action handling.

ActionStatus

Action status enumeration.

import type { ActionStatus } from '@cloudillo/types'

const status: ActionStatus =
  | 'P' // Pending (draft/unpublished)
  | 'A' // Active (default - published/finalized)
  | 'D' // Deleted (soft delete)
  | 'C' // Created (pending approval, e.g., connection requests)
  | 'N' // New (notification awaiting acknowledgment)

ProfileStatus

Profile status codes.

import type { ProfileStatus } from '@cloudillo/types'

const status: ProfileStatus =
  | 'A' // Active
  | 'T' // Trusted
  | 'B' // Blocked
  | 'M' // Muted
  | 'S' // Suspended

ProfileConnectionStatus

Connection status between profiles.

import type { ProfileConnectionStatus } from '@cloudillo/types'

// true = connected
// 'R' = request pending
// undefined = not connected

CommunityRole

Community role hierarchy.

import type { CommunityRole } from '@cloudillo/types'
import { ROLE_LEVELS } from '@cloudillo/types'

type CommunityRole =
  | 'public'      // Level 0 - Anyone
  | 'follower'    // Level 1 - Following the community
  | 'supporter'   // Level 2 - Supporter/subscriber
  | 'contributor' // Level 3 - Can create content
  | 'moderator'   // Level 4 - Can moderate
  | 'leader'      // Level 5 - Full admin access

// Use ROLE_LEVELS for permission checks
console.log(ROLE_LEVELS)
// { public: 0, follower: 1, supporter: 2, contributor: 3, moderator: 4, leader: 5 }

// Check if user has sufficient role
function hasPermission(userRole: CommunityRole, required: CommunityRole): boolean {
  return ROLE_LEVELS[userRole] >= ROLE_LEVELS[required]
}

NewAction

Data for creating a new action.

import type { NewAction } from '@cloudillo/types'

const newAction: NewAction = {
  type: 'POST',
  content: {
    text: 'Hello!',
    title: 'Greeting'
  },
  attachments: ['file_123']
}

Fields:

  • type: string - Action type
  • subType?: string - Action subtype
  • parentId?: string - Parent action ID
  • rootId?: string - Root action ID
  • audienceTag?: string - Target audience
  • content?: unknown - Action content
  • attachments?: string[] - File IDs
  • subject?: string - Subject/target
  • expiresAt?: number - Expiration time

ActionView

Extended action with resolved references and statistics.

import type { ActionView } from '@cloudillo/types'

const actionView: ActionView = {
  actionId: 'act_123',
  type: 'POST',
  issuerTag: 'alice@example.com',
  issuer: {
    idTag: 'alice@example.com',
    name: 'Alice Johnson',
    profilePic: '/file/b1~abc'
  },
  content: { text: 'Hello!' },
  createdAt: 1735000000,
  stat: {
    reactions: 5,
    comments: 3,
    ownReaction: 'LOVE'
  }
}

Additional Fields:

  • issuer: Profile - Resolved issuer profile
  • audience?: Profile - Resolved audience profile
  • stat?: ActionStat - Statistics

FileView

File metadata with owner information.

import type { FileView } from '@cloudillo/types'

const file: FileView = {
  fileId: 'f1~abc123',
  status: 'M',
  contentType: 'image/png',
  fileName: 'photo.png',
  fileTp: 'BLOB',
  createdAt: new Date('2025-01-01'),
  tags: ['vacation', 'beach'],
  owner: {
    idTag: 'alice@example.com',
    name: 'Alice'
  }
}

Fields:

  • fileId: string - File identifier
  • status: 'P' | 'M' - Pending or Metadata-ready
  • contentType: string - MIME type
  • fileName: string - Original filename
  • fileTp?: string - File type (CRDT/RTDB/BLOB)
  • createdAt: string | Date - Creation time
  • tags?: string[] - Tags
  • owner?: Profile - Owner profile
  • preset?: string - Image preset configuration

Runtime Validation

All types include runtime validators using @symbion/runtype:

import { ProfileValidator, ActionValidator } from '@cloudillo/types'

// Validate data at runtime
const data = await api.profiles.getOwn()

if (ProfileValidator.validate(data)) {
  // TypeScript knows data is a valid Profile
  console.log(data.idTag)
} else {
  console.error('Invalid profile data')
}

Type Guards

Use type guards to check types at runtime:

import { isAction, isProfile } from '@cloudillo/types'

function processData(data: unknown) {
  if (isAction(data)) {
    console.log('Action:', data.type)
  } else if (isProfile(data)) {
    console.log('Profile:', data.idTag)
  }
}

Enum Constants

Action Types

import { ACTION_TYPES } from '@cloudillo/types'

console.log(ACTION_TYPES)
// ['CONN', 'FLLW', 'POST', 'REPOST', 'REACT', 'CMNT', 'SHRE', 'MSG', 'FSHR']

// Use in UI
{ACTION_TYPES.map(type => (
  <option key={type} value={type}>{type}</option>
))}

Action Statuses

import { ACTION_STATUSES } from '@cloudillo/types'

console.log(ACTION_STATUSES)
// ['P', 'A', 'D', 'C', 'N']

Action Type Variants

Typed action structures for type-safe action creation.

User Relationships

import type { ConnectAction, FollowAction } from '@cloudillo/types'

// Connection request
const connect: ConnectAction = {
  type: 'CONN',
  subject: 'bob.cloudillo.net',      // Who to connect with
  content: 'Would love to connect!'  // Optional message
}

// Follow relationship
const follow: FollowAction = {
  type: 'FLLW',
  subject: 'news.cloudillo.net'      // Who to follow
}

Content Actions

import type { PostAction, CommentAction, ReactAction } from '@cloudillo/types'

// Create a post
const post: PostAction = {
  type: 'POST',
  subType: 'IMG',                    // Optional: IMG, VID, etc.
  content: 'Check out this photo!',
  attachments: ['fileId123'],        // Optional attachments
  audience: 'friends.cloudillo.net'  // Optional target audience
}

// Add a comment
const comment: CommentAction = {
  type: 'CMNT',
  parentId: 'actionId123',           // Parent action to comment on
  content: 'Great post!',
  attachments: []                    // Optional
}

// Add a reaction
const reaction: ReactAction = {
  type: 'REACT',
  parentId: 'actionId123',           // Action to react to
  content: 'LOVE'                    // Reaction type
}

Content Spreading

import type { AckAction, RepostAction, ShareAction } from '@cloudillo/types'

// Acknowledge content (accept to feed)
const ack: AckAction = {
  type: 'ACK',
  parentId: 'actionId123'            // Action to acknowledge
}

// Repost content
const repost: RepostAction = {
  type: 'REPOST',
  parentId: 'actionId123',           // Original action
  content: 'Adding my thoughts...'   // Optional comment
}

// Share directly to someone
const share: ShareAction = {
  type: 'SHRE',
  subject: 'actionId123',            // What to share
  audience: 'bob.cloudillo.net',     // Who to share with
  content: 'You might like this!'    // Optional message
}

Messages

import type { MessageAction } from '@cloudillo/types'

// Direct message
const dm: MessageAction = {
  type: 'MSG',
  subType: 'TEXT',
  content: 'Hello!',
  audience: 'bob.cloudillo.net'      // Recipient
}

// Group message (reply to conversation)
const groupMsg: MessageAction = {
  type: 'MSG',
  subType: 'TEXT',
  content: 'Thanks everyone!',
  parentId: 'conversationId123'      // Conversation ID
}

File Sharing

import type { FileShareAction } from '@cloudillo/types'

// Share a file with read access
const fileShare: FileShareAction = {
  type: 'FSHR',
  subType: 'READ',                   // 'READ' or 'WRITE'
  subject: 'fileId123',              // File to share
  audience: 'bob.cloudillo.net',     // Who to share with
  content: {
    fileName: 'document.pdf',
    contentType: 'application/pdf',
    fileTp: 'BLOB'
  }
}

Reaction Statistics

import type { ReactionStatAction } from '@cloudillo/types'

// Aggregated reaction stats (usually system-generated)
const stats: ReactionStatAction = {
  type: 'RSTAT',
  parentId: 'actionId123',
  content: {
    comment: 5,                      // Number of comments
    reactions: [10, 3, 1]            // Reaction counts by type
  }
}

ProfileInfo

Embedded profile information in actions.

import type { ProfileInfo } from '@cloudillo/types'

const info: ProfileInfo = {
  idTag: 'alice.cloudillo.net',
  name: 'Alice',                     // Optional
  profilePic: 'picId123',            // Optional
  type: 'person'                     // 'person' or 'community'
}

See Also