poptart_bluesky_text

Parse Bluesky post text into handles, links, hashtags, byte indices, and rich-text facet maps for the AT Protocol.

This package is a Poptart-compatible fork of bluesky_text. It keeps the small BlueskyText API while using poptart_xrpc for handle-to-DID lookups.

Features

  • Detects mentions, links, hashtags, and markdown links.
  • Tracks UTF-8 byte indices for app.bsky.richtext.facet records.
  • Builds facet JSON for mentions, links, and tags.
  • Splits long text without breaking grapheme clusters.
  • Handles Unicode text, emoji, and multilingual input.

Install

dependencies:
  poptart_bluesky_text: ^0.1.0

Usage

import 'package:poptart_bluesky_text/poptart_bluesky_text.dart';

Future<void> main() async {
  const text = BlueskyText(
    'Hello @alice.test, see https://example.com/docs and #poptart.',
  );

  final handles = text.handles;
  final links = text.links;
  final tags = text.tags;

  final facets = await Entities([...links, ...tags]).toFacets();

  assert(handles.single.value == '@alice.test');
  assert(facets.length == 2);
}

Mention facets resolve handles through com.atproto.identity.resolveHandle. If a handle cannot be resolved, that mention facet is skipped. Link and tag facets are built locally.

Common Tasks

Read Entities

const text = BlueskyText('Follow @alice.test and #poptart.');

final firstHandle = text.handles.single;
final firstTag = text.tags.single;

assert(firstHandle.type == EntityType.handle);
assert(firstTag.value == 'poptart');

Build Facets

const text = BlueskyText('Read https://example.com and #atproto.');

final facets = await text.entities.toFacets();

Split Long Text

final text = BlueskyText('A long post body...');

if (text.isLengthLimitExceeded) {
  final chunks = text.split();
  assert(chunks.every((chunk) => !chunk.isLengthLimitExceeded));
}

Example

See example/main.dart for a complete example.

Attribution

This package is derived from bluesky_text by Shinya Kato and contributors. The source is licensed under the BSD 3-Clause License. See LICENSE.