plaintext-casa
v0.3.1
Published
Library for parsing and working with plaintext.casa feeds
Maintainers
Readme
plaintext-casa
A TypeScript/JavaScript library for parsing and working with plaintext.casa feeds.
What is plaintext.casa?
plaintext.casa is a decentralized social network that uses plain text files over HTTP. This library provides the core functionality for parsing feeds, assembling timelines, and working with plaintext.casa content.
Installation
npm install plaintext-casa
# or
bun install plaintext-casaFeatures
- Parse feeds in multiple formats (Markdown, Org, AsciiDoc, plain text)
- Assemble timelines by fetching and combining posts from followed feeds
- Post updates - Support for the
supersedesfield to update posts while maintaining append-only feeds - Type-safe - Full TypeScript support with comprehensive type definitions
- Flexible - Supports custom metadata fields
- Zero dependencies - Core library has no external dependencies
Usage
Parse a Feed
import parseFeed from 'plaintext-casa'
const feedContent = `
# Alice's Feed
:author: Alice
:description: My plaintext.casa feed
**
:id: 2025-12-07T12:00:00Z
:tags: hello world
Hello from plaintext.casa!
`
const result = parseFeed(feedContent, 'md')
console.log(result.feed.title) // "Alice's Feed"
console.log(result.feed.posts.length) // 1Assemble a Timeline
import { assembleTimeline } from 'plaintext-casa'
const myFeed = parseFeed(feedContent, 'md').feed
const timeline = await assembleTimeline(myFeed, 'https://example.com/feed.md')
// Timeline contains posts from your feed and all followed feeds
timeline.posts.forEach(post => {
console.log(`${post.feedAuthor}: ${post.content}`)
})
// Check for any errors fetching followed feeds
if (timeline.errors.length > 0) {
console.error('Some feeds failed to load:', timeline.errors)
}API
parseFeed(feedString, fileType?, feedConfig?, postConfig?)
Parses a plaintext.casa feed from a string.
Parameters:
feedString: string- The raw feed contentfileType?: string- File extension hint ('md', 'org', 'adoc', 'txt')feedConfig?: ParserConfig- Optional feed parser configurationpostConfig?: ParserConfig- Optional post parser configuration
Returns: FeedParserResult containing:
feed: Feed- Parsed feed objectwarnings- Parser warningserrors- Parser errors
assembleTimeline(userFeed, userFeedUrl?)
Assembles a timeline by fetching and combining posts from all followed feeds. Automatically filters out superseded posts.
Parameters:
userFeed: Feed- The parsed user feeduserFeedUrl?: string- Optional URL of the user's feed
Returns: Promise<TimelineResult> containing:
posts: TimelinePost[]- All posts sorted chronologically with superseded posts filtered outerrors: Array<{url, error}>- Any errors fetching feeds
Types
Feed
interface Feed {
title: string
author: string
description: string
lang: string | null
avatar: string | null
links: string[]
follows: string[]
pages: string[]
about: string
posts: Post[]
}Post
interface Post {
id: string
date?: string
lang: string
tags: string
reply_to: URL
supersedes?: string
mood: string
content_warning: string
content: string
}TimelinePost
Extends Post with additional metadata:
interface TimelinePost extends Post {
feedTitle: string
feedAuthor: string
givenName?: string
feedUrl?: string
fetchedAt: Date
}Sorting
Posts in timelines are sorted chronologically (oldest first, newest last) using:
:date:field if present:id:field if it's a valid RFC 3339 timestamp- Fetch time as fallback
This allows custom IDs while maintaining chronological order.
Post Updates with Supersedes
The supersedes field allows you to update or correct posts while maintaining the append-only nature of plaintext.casa feeds.
When a post includes :supersedes: <post-id>, it indicates that this post replaces an older post. The timeline automatically filters out superseded posts, showing only the latest version.
Important: You can only supersede posts from your own feed. Cross-feed superseding is prevented to avoid censorship and maintain decentralization.
// Original post with an error
const feedWithError = `
**
:id: 2024-01-01T10:00:00Z
The Earth is flat.
`
// Correction using supersedes
const feedWithCorrection = `
**
:id: 2024-01-01T10:00:00Z
The Earth is flat.
**
:id: 2024-01-01T12:00:00Z
:supersedes: 2024-01-01T10:00:00Z
Correction: The Earth is round.
`
// Timeline will only show the correction
const timeline = await assembleTimeline(parseFeed(feedWithCorrection, 'md').feed)
// timeline.posts.length === 1 (only the corrected post)The original post remains in the feed file, but is filtered from timeline views.
Supported Formats
Right now, only Markdown is fully supported. AsciiDoc and Plaintext should also work, but are not explicitly tested.
- Markdown (
.md,.markdown) - AsciiDoc (
.adoc,.asciidoc) - Plain text (
.txt,.text)
Support planned
- Org mode (
.org) - Org Social compatible
Development
# Install dependencies
bun install
# Run tests
bun test
# Type check
bun run type-checkLicense
MIT
