Daily Bluesky bot for AT Mot. Invites players and congratulates yesterday's solvers.
0

Configure Feed

Select the types of activity you want to include in your feed.

at trunk 2.0 kB View raw
1/** A Bluesky richtext link facet (UTF-8 byte offsets, per the lexicon). */ 2export interface FacetLink { 3 index: { byteStart: number; byteEnd: number }; 4 features: Array<{ $type: 'app.bsky.richtext.facet#link'; uri: string }>; 5} 6 7/** A Bluesky richtext hashtag facet. The byte range covers the leading `#`; `tag` omits it. */ 8export interface FacetTag { 9 index: { byteStart: number; byteEnd: number }; 10 features: Array<{ $type: 'app.bsky.richtext.facet#tag'; tag: string }>; 11} 12 13export type Facet = FacetLink | FacetTag; 14 15const encoder = new TextEncoder(); 16 17const byteLen = (s: string): number => encoder.encode(s).length; 18 19/** Facet over the first occurrence of `url` in `text`; [] if it's not there. */ 20export function linkFacet(text: string, url: string): FacetLink[] { 21 const charIndex = text.indexOf(url); 22 if (charIndex === -1) return []; 23 const byteStart = byteLen(text.slice(0, charIndex)); 24 const byteEnd = byteStart + byteLen(url); 25 return [{ index: { byteStart, byteEnd }, features: [{ $type: 'app.bsky.richtext.facet#link', uri: url }] }]; 26} 27 28/** 29 * A hashtag at a word boundary: `#` then a letter then word chars. Requiring a 30 * leading letter means an all-digit token like the puzzle "#3" is not treated as 31 * a tag (matching Bluesky, which rejects all-numeric tags). 32 */ 33const TAG_RE = /(^|\s)(#[A-Za-z][A-Za-z0-9_]*)/g; 34 35/** One `#tag` facet per hashtag in `text` (UTF-8 byte offsets, in text order). */ 36export function tagFacets(text: string): FacetTag[] { 37 const out: FacetTag[] = []; 38 for (const m of text.matchAll(TAG_RE)) { 39 const lead = m[1] ?? ''; 40 const hashtag = m[2]!; // e.g. "#WordGame" 41 const start = m.index! + lead.length; // char index of the '#' 42 const byteStart = byteLen(text.slice(0, start)); 43 const byteEnd = byteStart + byteLen(hashtag); 44 out.push({ 45 index: { byteStart, byteEnd }, 46 features: [{ $type: 'app.bsky.richtext.facet#tag', tag: hashtag.slice(1) }], 47 }); 48 } 49 return out; 50}