Skip to content

Ivory

Ivory is a Mastodon client by Tapbots. Protocol Launcher allows you to generate Ivory URL scheme links.

Usage

There are two ways to use this library:

  • On-Demand import from subpaths enables tree-shaking and keeps bundles small.
  • Full Import from the root package is convenient but includes all app modules.

Pick On-Demand for production builds; Full Import is fine for quick scripts or demos.

Select Installation Method

On-Demand
Recommended. Optimized for production.
Full Import
Convenient. Good for quick scripts.

Notes

Tapbots documents acct as the account selector. It can be a fully qualified @user@host, a short @user, or blank for the currently active Ivory account. When acct is omitted, Protocol Launcher generates URLs such as ivory:///home.

This module only exposes the official Ivory URL shapes: tab URLs, openURL, status, user_profile, and post. callbackUrl is only available for the documented modal actions and serializes to the official callback_url query parameter.

Tabs

On-Demand
ts
import { openHome, openTimeline, openMentions, openLists, openFavorites, openBookmarks, openStatistics, openProfileTab, openSearch } from 'protocol-launcher/ivory'

const homeUrl = openHome()
const timelineUrl = openTimeline({ acct: '@alice' })
const mentionsUrl = openMentions({ acct: '@alice' })
const listsUrl = openLists()
const favoritesUrl = openFavorites()
const bookmarksUrl = openBookmarks()
const statisticsUrl = openStatistics()
const profileTabUrl = openProfileTab({ acct: '@alice@mastodon.social' })
const searchUrl = openSearch()

Open URL

On-Demand
ts
import { openUrl } from 'protocol-launcher/ivory'

const url = openUrl({
  acct: '@alice@mastodon.social',
  url: 'https://mastodon.social/@tapbots',
  callbackUrl: 'launcher://done',
})

Open Status

On-Demand
ts
import { openStatus } from 'protocol-launcher/ivory'

const url = openStatus({
  acct: '@alice@mastodon.social',
  statusId: '110123456789',
})

Open Profile

On-Demand
ts
import { openProfile } from 'protocol-launcher/ivory'

const url = openProfile({
  acct: '@alice@mastodon.social',
  userAcct: '@tapbots@mastodon.social',
})

Compose

On-Demand
ts
import { compose } from 'protocol-launcher/ivory'

const url = compose({
  acct: '@alice',
  callbackUrl: 'launcher://done',
})

Compose Text Path

On-Demand
ts
import { composeText } from 'protocol-launcher/ivory'

const url = composeText({
  acct: '@alice',
  text: 'Hello Ivory',
})

Compose Reply

On-Demand
ts
import { composeReply } from 'protocol-launcher/ivory'

const url = composeReply({
  acct: '@alice',
  text: 'Hello Ivory',
  inReplyToStatusUrl: 'https://mastodon.social/@tapbots/110123456789',
})

Generated URLs

ts
openHome()
// => 'ivory:///home'

openTimeline({ acct: '@alice' })
// => 'ivory://@alice/timeline'

openUrl({
  acct: '@alice@mastodon.social',
  url: 'https://mastodon.social/@tapbots',
  callbackUrl: 'launcher://done',
})
// => 'ivory://@alice@mastodon.social/openURL?url=https%3A%2F%2Fmastodon.social%2F%40tapbots&callback_url=launcher%3A%2F%2Fdone'

openStatus({
  acct: '@alice@mastodon.social',
  statusId: '110123456789',
})
// => 'ivory://@alice@mastodon.social/status/110123456789'

openProfile({
  acct: '@alice@mastodon.social',
  userAcct: '@tapbots@mastodon.social',
})
// => 'ivory://@alice@mastodon.social/user_profile/@tapbots@mastodon.social'

compose()
// => 'ivory:///post'

compose({
  acct: '@alice',
  callbackUrl: 'launcher://done',
})
// => 'ivory://@alice/post?callback_url=launcher%3A%2F%2Fdone'

composeText({
  acct: '@alice',
  text: 'Hello Ivory',
})
// => 'ivory://@alice/post/Hello%20Ivory'

composeReply({
  acct: '@alice',
  text: 'Hello Ivory',
  inReplyToStatusUrl: 'https://mastodon.social/@tapbots/110123456789',
})
// => 'ivory://@alice/post?text=Hello%20Ivory&in_reply_to_status_url=https%3A%2F%2Fmastodon.social%2F%40tapbots%2F110123456789'

Official Documentation