| 569 |
569 |
|
export interface CreateBlueskyPostOptions { |
| 570 |
570 |
|
title: string; |
| 571 |
571 |
|
description?: string; |
|
572 |
+ |
bskyPost?: string; |
| 572 |
573 |
|
canonicalUrl: string; |
| 573 |
574 |
|
coverImage?: BlobObject; |
| 574 |
575 |
|
publishedAt: string; // Used as createdAt for the post |
|
| 612 |
613 |
|
agent: Agent, |
| 613 |
614 |
|
options: CreateBlueskyPostOptions, |
| 614 |
615 |
|
): Promise<StrongRef> { |
| 615 |
|
- |
const { title, description, canonicalUrl, coverImage, publishedAt } = options; |
|
616 |
+ |
const { title, description, bskyPost, canonicalUrl, coverImage, publishedAt } = options; |
| 616 |
617 |
|
|
| 617 |
|
- |
// Build post text: title + description + URL |
|
618 |
+ |
// Build post text: title + description |
| 618 |
619 |
|
// Max 300 graphemes for Bluesky posts |
| 619 |
620 |
|
const MAX_GRAPHEMES = 300; |
| 620 |
621 |
|
|
| 621 |
622 |
|
let postText: string; |
| 622 |
|
- |
const urlPart = `\n\n${canonicalUrl}`; |
| 623 |
|
- |
const urlGraphemes = countGraphemes(urlPart); |
| 624 |
623 |
|
|
| 625 |
|
- |
if (description) { |
| 626 |
|
- |
// Try: title + description + URL |
| 627 |
|
- |
const fullText = `${title}\n\n${description}${urlPart}`; |
|
624 |
+ |
if (bskyPost) { |
|
625 |
+ |
// Custom bsky post overrides any default behavior |
|
626 |
+ |
postText = bskyPost; |
|
627 |
+ |
} |
|
628 |
+ |
else if (description) { |
|
629 |
+ |
// Try: title + description |
|
630 |
+ |
const fullText = `${title}\n\n${description}`; |
| 628 |
631 |
|
if (countGraphemes(fullText) <= MAX_GRAPHEMES) { |
| 629 |
632 |
|
postText = fullText; |
| 630 |
633 |
|
} else { |
|
| 632 |
635 |
|
const availableForDesc = |
| 633 |
636 |
|
MAX_GRAPHEMES - |
| 634 |
637 |
|
countGraphemes(title) - |
| 635 |
|
- |
countGraphemes("\n\n") - |
| 636 |
|
- |
urlGraphemes - |
| 637 |
638 |
|
countGraphemes("\n\n"); |
| 638 |
639 |
|
if (availableForDesc > 10) { |
| 639 |
640 |
|
const truncatedDesc = truncateToGraphemes( |
| 640 |
641 |
|
description, |
| 641 |
642 |
|
availableForDesc, |
| 642 |
643 |
|
); |
| 643 |
|
- |
postText = `${title}\n\n${truncatedDesc}${urlPart}`; |
|
644 |
+ |
postText = `${title}\n\n${truncatedDesc}`; |
| 644 |
645 |
|
} else { |
| 645 |
|
- |
// Just title + URL |
| 646 |
|
- |
postText = `${title}${urlPart}`; |
|
646 |
+ |
// Just title |
|
647 |
+ |
postText = `${title}`; |
| 647 |
648 |
|
} |
| 648 |
649 |
|
} |
| 649 |
650 |
|
} else { |
| 650 |
|
- |
// Just title + URL |
| 651 |
|
- |
postText = `${title}${urlPart}`; |
|
651 |
+ |
// Just title |
|
652 |
+ |
postText = `${title}`; |
| 652 |
653 |
|
} |
| 653 |
654 |
|
|
| 654 |
|
- |
// Final truncation if still too long (shouldn't happen but safety check) |
|
655 |
+ |
// Final truncation in case title or bskyPost are longer than expected |
| 655 |
656 |
|
if (countGraphemes(postText) > MAX_GRAPHEMES) { |
| 656 |
657 |
|
postText = truncateToGraphemes(postText, MAX_GRAPHEMES); |
| 657 |
658 |
|
} |
| 658 |
659 |
|
|
| 659 |
|
- |
// Calculate byte indices for the URL facet |
| 660 |
|
- |
const encoder = new TextEncoder(); |
| 661 |
|
- |
const urlStartInText = postText.lastIndexOf(canonicalUrl); |
| 662 |
|
- |
const beforeUrl = postText.substring(0, urlStartInText); |
| 663 |
|
- |
const byteStart = encoder.encode(beforeUrl).length; |
| 664 |
|
- |
const byteEnd = byteStart + encoder.encode(canonicalUrl).length; |
| 665 |
|
- |
|
| 666 |
|
- |
// Build facets for the URL link |
| 667 |
|
- |
const facets = [ |
| 668 |
|
- |
{ |
| 669 |
|
- |
index: { |
| 670 |
|
- |
byteStart, |
| 671 |
|
- |
byteEnd, |
| 672 |
|
- |
}, |
| 673 |
|
- |
features: [ |
| 674 |
|
- |
{ |
| 675 |
|
- |
$type: "app.bsky.richtext.facet#link", |
| 676 |
|
- |
uri: canonicalUrl, |
| 677 |
|
- |
}, |
| 678 |
|
- |
], |
| 679 |
|
- |
}, |
| 680 |
|
- |
]; |
| 681 |
|
- |
|
| 682 |
660 |
|
// Build external embed |
| 683 |
661 |
|
const embed: Record<string, unknown> = { |
| 684 |
662 |
|
$type: "app.bsky.embed.external", |
|
| 698 |
676 |
|
const record: Record<string, unknown> = { |
| 699 |
677 |
|
$type: "app.bsky.feed.post", |
| 700 |
678 |
|
text: postText, |
| 701 |
|
- |
facets, |
| 702 |
679 |
|
embed, |
| 703 |
680 |
|
createdAt: new Date(publishedAt).toISOString(), |
| 704 |
681 |
|
}; |