@cyanheads/bluesky-mcp-server 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. package/AGENTS.md +346 -0
  2. package/CLAUDE.md +346 -0
  3. package/Dockerfile +99 -0
  4. package/LICENSE +201 -0
  5. package/README.md +307 -0
  6. package/changelog/0.1.x/0.1.1.md +24 -0
  7. package/changelog/template.md +127 -0
  8. package/dist/index.d.ts +7 -0
  9. package/dist/index.d.ts.map +1 -0
  10. package/dist/index.js +43 -0
  11. package/dist/index.js.map +1 -0
  12. package/dist/mcp-server/resources/definitions/bsky-profile.resource.d.ts +15 -0
  13. package/dist/mcp-server/resources/definitions/bsky-profile.resource.d.ts.map +1 -0
  14. package/dist/mcp-server/resources/definitions/bsky-profile.resource.js +54 -0
  15. package/dist/mcp-server/resources/definitions/bsky-profile.resource.js.map +1 -0
  16. package/dist/mcp-server/tools/definitions/bsky-get-author-feed.tool.d.ts +49 -0
  17. package/dist/mcp-server/tools/definitions/bsky-get-author-feed.tool.d.ts.map +1 -0
  18. package/dist/mcp-server/tools/definitions/bsky-get-author-feed.tool.js +217 -0
  19. package/dist/mcp-server/tools/definitions/bsky-get-author-feed.tool.js.map +1 -0
  20. package/dist/mcp-server/tools/definitions/bsky-get-follows.tool.d.ts +43 -0
  21. package/dist/mcp-server/tools/definitions/bsky-get-follows.tool.d.ts.map +1 -0
  22. package/dist/mcp-server/tools/definitions/bsky-get-follows.tool.js +165 -0
  23. package/dist/mcp-server/tools/definitions/bsky-get-follows.tool.js.map +1 -0
  24. package/dist/mcp-server/tools/definitions/bsky-get-post-thread.tool.d.ts +24 -0
  25. package/dist/mcp-server/tools/definitions/bsky-get-post-thread.tool.d.ts.map +1 -0
  26. package/dist/mcp-server/tools/definitions/bsky-get-post-thread.tool.js +166 -0
  27. package/dist/mcp-server/tools/definitions/bsky-get-post-thread.tool.js.map +1 -0
  28. package/dist/mcp-server/tools/definitions/bsky-get-profile.tool.d.ts +32 -0
  29. package/dist/mcp-server/tools/definitions/bsky-get-profile.tool.d.ts.map +1 -0
  30. package/dist/mcp-server/tools/definitions/bsky-get-profile.tool.js +117 -0
  31. package/dist/mcp-server/tools/definitions/bsky-get-profile.tool.js.map +1 -0
  32. package/dist/mcp-server/tools/definitions/bsky-get-trending.tool.d.ts +21 -0
  33. package/dist/mcp-server/tools/definitions/bsky-get-trending.tool.d.ts.map +1 -0
  34. package/dist/mcp-server/tools/definitions/bsky-get-trending.tool.js +81 -0
  35. package/dist/mcp-server/tools/definitions/bsky-get-trending.tool.js.map +1 -0
  36. package/dist/mcp-server/tools/definitions/bsky-search-actors.tool.d.ts +27 -0
  37. package/dist/mcp-server/tools/definitions/bsky-search-actors.tool.d.ts.map +1 -0
  38. package/dist/mcp-server/tools/definitions/bsky-search-actors.tool.js +100 -0
  39. package/dist/mcp-server/tools/definitions/bsky-search-actors.tool.js.map +1 -0
  40. package/dist/mcp-server/tools/definitions/bsky-search-posts.tool.d.ts +47 -0
  41. package/dist/mcp-server/tools/definitions/bsky-search-posts.tool.d.ts.map +1 -0
  42. package/dist/mcp-server/tools/definitions/bsky-search-posts.tool.js +233 -0
  43. package/dist/mcp-server/tools/definitions/bsky-search-posts.tool.js.map +1 -0
  44. package/dist/services/bluesky/bluesky-service.d.ts +68 -0
  45. package/dist/services/bluesky/bluesky-service.d.ts.map +1 -0
  46. package/dist/services/bluesky/bluesky-service.js +287 -0
  47. package/dist/services/bluesky/bluesky-service.js.map +1 -0
  48. package/dist/services/bluesky/types.d.ts +126 -0
  49. package/dist/services/bluesky/types.d.ts.map +1 -0
  50. package/dist/services/bluesky/types.js +6 -0
  51. package/dist/services/bluesky/types.js.map +1 -0
  52. package/package.json +102 -0
  53. package/server.json +99 -0
@@ -0,0 +1,233 @@
1
+ /**
2
+ * @fileoverview Full-text search across public Bluesky posts.
3
+ * @module mcp-server/tools/definitions/bsky-search-posts
4
+ */
5
+ import { tool, z } from '@cyanheads/mcp-ts-core';
6
+ import { getBlueskyService } from '../../../services/bluesky/bluesky-service.js';
7
+ /** Embed uses passthrough to flow all sub-fields through structuredContent while format() renders the key data. */
8
+ const EmbedSchema = z
9
+ .object({})
10
+ .passthrough()
11
+ .describe('Media or link embed attached to this post. ' +
12
+ 'type: "images" | "external" | "record" | "video" | "unknown". ' +
13
+ 'images: array of { url, alt, aspectRatio? }. ' +
14
+ 'external: { uri, title, description, thumb? }. ' +
15
+ 'record: { uri, cid, text?, authorHandle? }. ' +
16
+ 'video: { playlist?, thumbnail?, presentation?, aspectRatio? }. ' +
17
+ 'unknown: { raw }.');
18
+ const PostSchema = z
19
+ .object({
20
+ uri: z
21
+ .string()
22
+ .describe('AT-URI of this post (format: at://did:plc:<id>/app.bsky.feed.post/<rkey>). ' +
23
+ 'Pass to bsky_get_post_thread to read the full conversation.'),
24
+ cid: z.string().describe('Content Identifier (CID) of the post record.'),
25
+ text: z.string().describe('Full text content of the post.'),
26
+ author: z
27
+ .object({
28
+ did: z
29
+ .string()
30
+ .describe('Permanent DID of the author, e.g. "did:plc:z72i7hdynmk6r22z27h6tvur".'),
31
+ handle: z
32
+ .string()
33
+ .describe('Human-readable handle of the author, e.g. "alice.bsky.social".'),
34
+ displayName: z.string().optional().describe('Display name set by the author.'),
35
+ avatar: z.string().optional().describe('URL of the author avatar image.'),
36
+ })
37
+ .describe('Author of this post.'),
38
+ replyCount: z.number().optional().describe('Number of replies.'),
39
+ repostCount: z.number().optional().describe('Number of reposts.'),
40
+ likeCount: z.number().optional().describe('Number of likes.'),
41
+ quoteCount: z.number().optional().describe('Number of quote posts.'),
42
+ indexedAt: z
43
+ .string()
44
+ .optional()
45
+ .describe('ISO 8601 timestamp when the AppView indexed this post.'),
46
+ createdAt: z.string().optional().describe('ISO 8601 timestamp when the post was created.'),
47
+ labels: z
48
+ .array(z
49
+ .object({
50
+ val: z
51
+ .string()
52
+ .describe('Label value (content warning or moderation tag, e.g. "porn", "spam").'),
53
+ })
54
+ .describe('A moderation label.'))
55
+ .optional()
56
+ .describe('Moderation labels on this post.'),
57
+ embed: EmbedSchema.optional().describe('Media or link embed, if any.'),
58
+ replyToUri: z.string().optional().describe('AT-URI of the parent post if this is a reply.'),
59
+ })
60
+ .describe('A single post matching the search query.');
61
+ export const bskySearchPosts = tool('bsky_search_posts', {
62
+ title: 'Search Bluesky Posts',
63
+ description: 'Full-text search across public Bluesky posts. Filters by author (handle or DID), language ' +
64
+ '(BCP-47 code, e.g. "en"), hashtag (without the # prefix), date range (ISO 8601), and sort order. ' +
65
+ 'Returns posts with text, author info, engagement counts (likes/reposts/replies), normalized embeds, ' +
66
+ 'AT-URIs for thread drilling, and hitsTotal when the API reports the total number of matching posts. ' +
67
+ 'This is the primary entry point for social listening — pass any AT-URI from results to ' +
68
+ 'bsky_get_post_thread to read the full conversation.',
69
+ annotations: { readOnlyHint: true, idempotentHint: true, openWorldHint: true },
70
+ input: z.object({
71
+ query: z
72
+ .string()
73
+ .max(500)
74
+ .describe('Full-text search query, e.g. "climate change" or "#ai announcement".'),
75
+ author_handle: z
76
+ .string()
77
+ .max(253)
78
+ .optional()
79
+ .describe('Filter to posts by this author. Accepts handle (e.g. "bsky.app") or DID. ' +
80
+ 'Use bsky_get_profile to resolve a name to a handle first.'),
81
+ language: z
82
+ .string()
83
+ .max(10)
84
+ .optional()
85
+ .describe('BCP-47 language code to restrict results to, e.g. "en", "ja", "es".'),
86
+ tag: z
87
+ .string()
88
+ .max(100)
89
+ .optional()
90
+ .describe('Hashtag to filter by — provide without the # prefix, e.g. "ai" not "#ai".'),
91
+ since: z
92
+ .string()
93
+ .max(32)
94
+ .optional()
95
+ .describe('Return posts after this ISO 8601 datetime (inclusive), e.g. "2025-01-01T00:00:00Z".'),
96
+ until: z
97
+ .string()
98
+ .max(32)
99
+ .optional()
100
+ .describe('Return posts before this ISO 8601 datetime (inclusive), e.g. "2025-12-31T23:59:59Z".'),
101
+ sort: z
102
+ .enum(['top', 'latest'])
103
+ .default('latest')
104
+ .describe('"latest" returns posts in reverse-chronological order (default). ' +
105
+ '"top" returns by engagement score.'),
106
+ limit: z
107
+ .number()
108
+ .int()
109
+ .min(1)
110
+ .max(100)
111
+ .default(25)
112
+ .describe('Maximum posts to return (1–100). Default 25.'),
113
+ cursor: z
114
+ .string()
115
+ .max(2048)
116
+ .optional()
117
+ .describe('Opaque pagination cursor from a previous response. Omit for the first page.'),
118
+ }),
119
+ output: z.object({
120
+ posts: z.array(PostSchema).describe('Posts matching the search query.'),
121
+ cursor: z
122
+ .string()
123
+ .optional()
124
+ .describe('Opaque cursor for the next page. Absent on the last page.'),
125
+ hitsTotal: z
126
+ .number()
127
+ .optional()
128
+ .describe('Total number of posts matching this query across all pages, when reported by the API. ' +
129
+ 'Use to communicate result scale without fetching every page.'),
130
+ }),
131
+ enrichment: {
132
+ totalReturned: z.number().describe('Number of posts in this response page.'),
133
+ },
134
+ async handler(input, ctx) {
135
+ ctx.log.info('Searching Bluesky posts', {
136
+ query: input.query,
137
+ sort: input.sort,
138
+ limit: input.limit,
139
+ });
140
+ const result = await getBlueskyService().searchPosts({
141
+ q: input.query,
142
+ ...(input.author_handle ? { author: input.author_handle } : {}),
143
+ ...(input.language ? { lang: input.language } : {}),
144
+ ...(input.tag ? { tag: input.tag } : {}),
145
+ ...(input.since ? { since: input.since } : {}),
146
+ ...(input.until ? { until: input.until } : {}),
147
+ sort: input.sort,
148
+ limit: input.limit,
149
+ ...(input.cursor ? { cursor: input.cursor } : {}),
150
+ }, ctx);
151
+ ctx.enrich({ totalReturned: result.posts.length });
152
+ if (result.posts.length === 0) {
153
+ ctx.enrich.notice(`No posts matched "${input.query}". Try broader terms, different spelling, or remove filters.`);
154
+ }
155
+ return {
156
+ posts: result.posts,
157
+ ...(result.cursor ? { cursor: result.cursor } : {}),
158
+ ...(result.hitsTotal != null ? { hitsTotal: result.hitsTotal } : {}),
159
+ };
160
+ },
161
+ format: (result) => {
162
+ if (result.posts.length === 0) {
163
+ return [{ type: 'text', text: 'No posts matched this query.' }];
164
+ }
165
+ const header = [];
166
+ if (result.hitsTotal != null)
167
+ header.push(`**${result.hitsTotal.toLocaleString()} total matches** (showing ${result.posts.length})`);
168
+ const lines = result.posts.map((p) => {
169
+ const parts = [];
170
+ const author = p.author.displayName
171
+ ? `${p.author.displayName} (@${p.author.handle})`
172
+ : `@${p.author.handle}`;
173
+ parts.push(`### ${author}`);
174
+ parts.push(`**AT-URI:** \`${p.uri}\` | **CID:** \`${p.cid}\``);
175
+ parts.push(`**Author DID:** \`${p.author.did}\``);
176
+ parts.push(p.text);
177
+ const meta = [];
178
+ if (p.likeCount != null)
179
+ meta.push(`${p.likeCount} likes`);
180
+ if (p.repostCount != null)
181
+ meta.push(`${p.repostCount} reposts`);
182
+ if (p.replyCount != null)
183
+ meta.push(`${p.replyCount} replies`);
184
+ if (p.quoteCount != null)
185
+ meta.push(`${p.quoteCount} quotes`);
186
+ if (meta.length)
187
+ parts.push(`*${meta.join(' · ')}*`);
188
+ if (p.createdAt)
189
+ parts.push(`*Created: ${p.createdAt}*`);
190
+ if (p.indexedAt)
191
+ parts.push(`*Indexed: ${p.indexedAt}*`);
192
+ if (p.embed) {
193
+ const embed = p.embed;
194
+ const embedType = embed.type;
195
+ if (embedType === 'images') {
196
+ const images = embed.images;
197
+ if (images?.length) {
198
+ parts.push(`📷 ${images.length} image(s): ${images.map((img) => `${img.url} [${img.alt}]`).join(', ')}`);
199
+ }
200
+ }
201
+ else if (embedType === 'external') {
202
+ parts.push(`🔗 [${embed.title}](${embed.uri}): ${embed.description}`);
203
+ }
204
+ else if (embedType === 'record') {
205
+ parts.push(`💬 Quoted: \`${embed.uri}\``);
206
+ if (embed.text)
207
+ parts.push(` > ${embed.text}`);
208
+ }
209
+ else if (embedType === 'video') {
210
+ const vid = embed;
211
+ const label = vid.presentation === 'gif' ? '🎞 GIF' : '🎬 Video';
212
+ if (vid.thumbnail)
213
+ parts.push(`${label}: ${vid.thumbnail}`);
214
+ else
215
+ parts.push(label);
216
+ }
217
+ }
218
+ if (p.replyToUri)
219
+ parts.push(`↩ Reply to \`${p.replyToUri}\``);
220
+ if (p.author.avatar)
221
+ parts.push(`**Avatar:** ${p.author.avatar}`);
222
+ if (p.labels?.length)
223
+ parts.push(`**Labels:** ${p.labels.map((l) => l.val).join(', ')}`);
224
+ return parts.join('\n');
225
+ });
226
+ const body = lines.join('\n\n---\n\n');
227
+ const footer = result.cursor ? `\n\n---\n*cursor: \`${result.cursor}\`*` : '';
228
+ return [
229
+ { type: 'text', text: (header.length ? `${header.join('\n')}\n\n` : '') + body + footer },
230
+ ];
231
+ },
232
+ });
233
+ //# sourceMappingURL=bsky-search-posts.tool.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bsky-search-posts.tool.js","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/bsky-search-posts.tool.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,68 @@
1
+ /**
2
+ * @fileoverview BlueskyService — AT Protocol AppView public read client.
3
+ * Wraps https://api.bsky.app/xrpc/ with retry/timeout and response normalization.
4
+ * @module services/bluesky/bluesky-service
5
+ */
6
+ import type { Context } from '@cyanheads/mcp-ts-core';
7
+ import type { ActorProfile, AuthorFeedResult, GraphResult, SearchActorsResult, SearchPostsResult, ThreadPost, TrendsResult } from './types.js';
8
+ /** Public-read AT Protocol AppView client. No authentication required. */
9
+ export declare class BlueskyService {
10
+ /** @internal Build a full XRPC URL with query params. */
11
+ private buildUrl;
12
+ /** @internal Fetch JSON from the AppView with retry/timeout. Throws ServiceUnavailable on upstream failure. */
13
+ private get;
14
+ /** Full-text post search. */
15
+ searchPosts(params: {
16
+ q: string;
17
+ author?: string;
18
+ lang?: string;
19
+ tag?: string;
20
+ since?: string;
21
+ until?: string;
22
+ sort?: 'top' | 'latest';
23
+ limit?: number;
24
+ cursor?: string;
25
+ }, ctx: Context): Promise<SearchPostsResult>;
26
+ /** Fetch an actor's public profile. */
27
+ getProfile(actor: string, ctx: Context): Promise<ActorProfile>;
28
+ /** Get an author's recent feed. */
29
+ getAuthorFeed(params: {
30
+ actor: string;
31
+ filter?: string;
32
+ limit?: number;
33
+ cursor?: string;
34
+ }, ctx: Context): Promise<AuthorFeedResult>;
35
+ /** Fetch the full conversation thread for a post by AT-URI. */
36
+ getPostThread(params: {
37
+ uri: string;
38
+ depth?: number;
39
+ parentHeight?: number;
40
+ }, ctx: Context): Promise<ThreadPost>;
41
+ /** Search for actors by name / handle fragment. */
42
+ searchActors(params: {
43
+ q: string;
44
+ limit?: number;
45
+ cursor?: string;
46
+ }, ctx: Context): Promise<SearchActorsResult>;
47
+ /** Get followers of an actor. */
48
+ getFollowers(params: {
49
+ actor: string;
50
+ limit?: number;
51
+ cursor?: string;
52
+ }, ctx: Context): Promise<GraphResult>;
53
+ /** Get accounts an actor follows. */
54
+ getFollows(params: {
55
+ actor: string;
56
+ limit?: number;
57
+ cursor?: string;
58
+ }, ctx: Context): Promise<GraphResult>;
59
+ /** Fetch real-time trending topics (app.bsky.unspecced.getTrends — unspecced endpoint, may change). */
60
+ getTrends(params: {
61
+ limit?: number;
62
+ }, ctx: Context): Promise<TrendsResult>;
63
+ }
64
+ /** Initialize the BlueskyService singleton. Call once in createApp setup(). */
65
+ export declare function initBlueskyService(): void;
66
+ /** Get the initialized BlueskyService singleton. Throws if not yet initialized. */
67
+ export declare function getBlueskyService(): BlueskyService;
68
+ //# sourceMappingURL=bluesky-service.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bluesky-service.d.ts","sourceRoot":"","sources":["../../../src/services/bluesky/bluesky-service.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,wBAAwB,CAAC;AAGtD,OAAO,KAAK,EACV,YAAY,EACZ,gBAAgB,EAEhB,WAAW,EAGX,kBAAkB,EAClB,iBAAiB,EACjB,UAAU,EACV,YAAY,EACb,MAAM,YAAY,CAAC;AAwNpB,0EAA0E;AAC1E,qBAAa,cAAc;IACzB,yDAAyD;IACzD,OAAO,CAAC,QAAQ;IAahB,+GAA+G;IAC/G,OAAO,CAAC,GAAG;IA4CX,6BAA6B;IACvB,WAAW,CACf,MAAM,EAAE;QACN,CAAC,EAAE,MAAM,CAAC;QACV,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,GAAG,CAAC,EAAE,MAAM,CAAC;QACb,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,IAAI,CAAC,EAAE,KAAK,GAAG,QAAQ,CAAC;QACxB,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,MAAM,CAAC,EAAE,MAAM,CAAC;KACjB,EACD,GAAG,EAAE,OAAO,GACX,OAAO,CAAC,iBAAiB,CAAC;IAuB7B,uCAAuC;IACjC,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,OAAO,GAAG,OAAO,CAAC,YAAY,CAAC;IAKpE,mCAAmC;IAC7B,aAAa,CACjB,MAAM,EAAE;QACN,KAAK,EAAE,MAAM,CAAC;QACd,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,MAAM,CAAC,EAAE,MAAM,CAAC;KACjB,EACD,GAAG,EAAE,OAAO,GACX,OAAO,CAAC,gBAAgB,CAAC;IAiB5B,+DAA+D;IACzD,aAAa,CACjB,MAAM,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,YAAY,CAAC,EAAE,MAAM,CAAA;KAAE,EAC9D,GAAG,EAAE,OAAO,GACX,OAAO,CAAC,UAAU,CAAC;IAatB,mDAAmD;IAC7C,YAAY,CAChB,MAAM,EAAE;QAAE,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE,EACtD,GAAG,EAAE,OAAO,GACX,OAAO,CAAC,kBAAkB,CAAC;IAgB9B,iCAAiC;IAC3B,YAAY,CAChB,MAAM,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE,EAC1D,GAAG,EAAE,OAAO,GACX,OAAO,CAAC,WAAW,CAAC;IAqBvB,qCAAqC;IAC/B,UAAU,CACd,MAAM,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE,EAC1D,GAAG,EAAE,OAAO,GACX,OAAO,CAAC,WAAW,CAAC;IAiBvB,uGAAuG;IACjG,SAAS,CAAC,MAAM,EAAE;QAAE,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,EAAE,GAAG,EAAE,OAAO,GAAG,OAAO,CAAC,YAAY,CAAC;CAyBjF;AAQD,+EAA+E;AAC/E,wBAAgB,kBAAkB,IAAI,IAAI,CAEzC;AAED,mFAAmF;AACnF,wBAAgB,iBAAiB,IAAI,cAAc,CAKlD"}
@@ -0,0 +1,287 @@
1
+ /**
2
+ * @fileoverview BlueskyService — AT Protocol AppView public read client.
3
+ * Wraps https://api.bsky.app/xrpc/ with retry/timeout and response normalization.
4
+ * @module services/bluesky/bluesky-service
5
+ */
6
+ import { serviceUnavailable } from '@cyanheads/mcp-ts-core/errors';
7
+ import { fetchWithTimeout, withRetry } from '@cyanheads/mcp-ts-core/utils';
8
+ /** @internal Bluesky AppView base URL — api.bsky.app avoids the 403s that public.api.bsky.app returns for searchPosts from some IPs. */
9
+ const BASE_URL = 'https://api.bsky.app';
10
+ /** @internal Request timeout in milliseconds. */
11
+ const TIMEOUT_MS = 15_000;
12
+ /** @internal User-Agent header sent on every request. */
13
+ const USER_AGENT = '@cyanheads/bluesky-mcp-server/0.1.0';
14
+ // ---------------------------------------------------------------------------
15
+ // Normalization helpers
16
+ // ---------------------------------------------------------------------------
17
+ function normalizeLabel(r) {
18
+ return { val: r.val, ...(r.src ? { src: r.src } : {}), ...(r.cts ? { cts: r.cts } : {}) };
19
+ }
20
+ function normalizeActor(r) {
21
+ return {
22
+ did: r.did,
23
+ handle: r.handle,
24
+ ...(r.displayName ? { displayName: r.displayName } : {}),
25
+ ...(r.description ? { description: r.description } : {}),
26
+ ...(r.avatar ? { avatar: r.avatar } : {}),
27
+ ...(typeof r.followersCount === 'number' ? { followersCount: r.followersCount } : {}),
28
+ ...(typeof r.followsCount === 'number' ? { followsCount: r.followsCount } : {}),
29
+ ...(typeof r.postsCount === 'number' ? { postsCount: r.postsCount } : {}),
30
+ ...(r.labels?.length ? { labels: r.labels.map(normalizeLabel) } : {}),
31
+ ...(r.indexedAt ? { indexedAt: r.indexedAt } : {}),
32
+ ...(r.createdAt ? { createdAt: r.createdAt } : {}),
33
+ ...(r.pinnedPost?.uri ? { pinnedPostUri: r.pinnedPost.uri } : {}),
34
+ };
35
+ }
36
+ function normalizeEmbed(r) {
37
+ if (!r)
38
+ return;
39
+ const type = r.$type ?? '';
40
+ if (type.includes('embed.images') || r.images) {
41
+ const images = (r.images ?? []).map((img) => ({
42
+ url: img.fullsize ?? img.thumb ?? '',
43
+ alt: img.alt ?? '',
44
+ ...(img.aspectRatio?.width != null && img.aspectRatio?.height != null
45
+ ? { aspectRatio: { width: img.aspectRatio.width, height: img.aspectRatio.height } }
46
+ : {}),
47
+ }));
48
+ return { type: 'images', images };
49
+ }
50
+ if (type.includes('embed.external') || r.external) {
51
+ const ext = r.external ?? {};
52
+ return {
53
+ type: 'external',
54
+ uri: ext.uri ?? '',
55
+ title: ext.title ?? '',
56
+ description: ext.description ?? '',
57
+ ...(ext.thumb ? { thumb: ext.thumb } : {}),
58
+ };
59
+ }
60
+ if (type.includes('embed.record') || r.record) {
61
+ const rec = r.record ?? {};
62
+ return {
63
+ type: 'record',
64
+ uri: rec.uri ?? '',
65
+ cid: rec.cid ?? '',
66
+ ...(rec.value?.text ? { text: rec.value.text } : {}),
67
+ ...(rec.author?.handle ? { authorHandle: rec.author.handle } : {}),
68
+ };
69
+ }
70
+ if (type.includes('embed.video')) {
71
+ return {
72
+ type: 'video',
73
+ ...(r.playlist ? { playlist: r.playlist } : {}),
74
+ ...(r.thumbnail ? { thumbnail: r.thumbnail } : {}),
75
+ ...(r.presentation ? { presentation: r.presentation } : {}),
76
+ ...(r.aspectRatio?.width != null && r.aspectRatio?.height != null
77
+ ? { aspectRatio: { width: r.aspectRatio.width, height: r.aspectRatio.height } }
78
+ : {}),
79
+ };
80
+ }
81
+ return { type: 'unknown', raw: type };
82
+ }
83
+ function normalizePost(r) {
84
+ const embed = normalizeEmbed(r.embed);
85
+ return {
86
+ uri: r.uri,
87
+ cid: r.cid,
88
+ text: r.record.text,
89
+ author: normalizeActor(r.author),
90
+ ...(typeof r.replyCount === 'number' ? { replyCount: r.replyCount } : {}),
91
+ ...(typeof r.repostCount === 'number' ? { repostCount: r.repostCount } : {}),
92
+ ...(typeof r.likeCount === 'number' ? { likeCount: r.likeCount } : {}),
93
+ ...(typeof r.quoteCount === 'number' ? { quoteCount: r.quoteCount } : {}),
94
+ ...(r.indexedAt ? { indexedAt: r.indexedAt } : {}),
95
+ ...(r.record.createdAt ? { createdAt: r.record.createdAt } : {}),
96
+ ...(r.labels?.length
97
+ ? {
98
+ labels: r.labels.map((l) => ({
99
+ val: l.val ?? '',
100
+ ...(l.src ? { src: l.src } : {}),
101
+ ...(l.cts ? { cts: l.cts } : {}),
102
+ })),
103
+ }
104
+ : {}),
105
+ ...(embed ? { embed } : {}),
106
+ ...(r.record.reply?.parent?.uri ? { replyToUri: r.record.reply.parent.uri } : {}),
107
+ };
108
+ }
109
+ /** @internal Sentinel PostView used for truncated/not-found thread stubs. */
110
+ const STUB_POST = { uri: '', cid: '', text: '', author: { did: '', handle: '' } };
111
+ function normalizeThread(node) {
112
+ const typeStr = node.$type ?? '';
113
+ if (typeStr.includes('threadViewPostMore')) {
114
+ // The API returns a stub indicating there are more replies — surface as truncated
115
+ return { post: STUB_POST, truncated: true };
116
+ }
117
+ if (typeStr.includes('threadViewPostNotFound') || !node.post) {
118
+ return { post: STUB_POST, notFound: true };
119
+ }
120
+ const result = { post: normalizePost(node.post) };
121
+ if (node.parent)
122
+ result.parent = normalizeThread(node.parent);
123
+ if (node.replies?.length)
124
+ result.replies = node.replies.map(normalizeThread);
125
+ return result;
126
+ }
127
+ // ---------------------------------------------------------------------------
128
+ // BlueskyService class
129
+ // ---------------------------------------------------------------------------
130
+ /** Public-read AT Protocol AppView client. No authentication required. */
131
+ export class BlueskyService {
132
+ /** @internal Build a full XRPC URL with query params. */
133
+ buildUrl(lexicon, params) {
134
+ const url = new URL(`${BASE_URL}/xrpc/${lexicon}`);
135
+ for (const [k, v] of Object.entries(params)) {
136
+ if (v !== undefined && v !== '') {
137
+ url.searchParams.set(k, String(v));
138
+ }
139
+ }
140
+ return url.toString();
141
+ }
142
+ /** @internal Fetch JSON from the AppView with retry/timeout. Throws ServiceUnavailable on upstream failure. */
143
+ get(lexicon, params, ctx) {
144
+ const url = this.buildUrl(lexicon, params);
145
+ return withRetry(async () => {
146
+ const response = await fetchWithTimeout(url, TIMEOUT_MS, ctx, {
147
+ headers: { 'User-Agent': USER_AGENT, Accept: 'application/json' },
148
+ signal: ctx.signal,
149
+ });
150
+ const text = await response.text();
151
+ if (/^\s*<(!DOCTYPE\s+html|html[\s>])/i.test(text)) {
152
+ throw serviceUnavailable('Bluesky API returned HTML — likely rate-limited or temporarily unavailable.');
153
+ }
154
+ try {
155
+ return JSON.parse(text);
156
+ }
157
+ catch {
158
+ throw serviceUnavailable('Bluesky API returned unparseable response.');
159
+ }
160
+ }, {
161
+ operation: `BlueskyService.${lexicon}`,
162
+ // Context is a superset of RequestContext — the logger strips non-serializable fields.
163
+ // biome-ignore lint/suspicious/noExplicitAny: ctx is a superset of RequestContext; cast is intentional
164
+ context: ctx,
165
+ baseDelayMs: 500,
166
+ signal: ctx.signal,
167
+ });
168
+ }
169
+ // ---------------------------------------------------------------------------
170
+ // Public API methods
171
+ // ---------------------------------------------------------------------------
172
+ /** Full-text post search. */
173
+ async searchPosts(params, ctx) {
174
+ const raw = await this.get('app.bsky.feed.searchPosts', {
175
+ q: params.q,
176
+ ...(params.author ? { author: params.author } : {}),
177
+ ...(params.lang ? { lang: params.lang } : {}),
178
+ ...(params.tag ? { tag: `#${params.tag}`.replace(/^##/, '#') } : {}),
179
+ ...(params.since ? { since: params.since } : {}),
180
+ ...(params.until ? { until: params.until } : {}),
181
+ sort: params.sort ?? 'latest',
182
+ limit: params.limit ?? 25,
183
+ ...(params.cursor ? { cursor: params.cursor } : {}),
184
+ }, ctx);
185
+ return {
186
+ posts: (raw.posts ?? []).map(normalizePost),
187
+ ...(raw.cursor ? { cursor: raw.cursor } : {}),
188
+ ...(typeof raw.hitsTotal === 'number' ? { hitsTotal: raw.hitsTotal } : {}),
189
+ };
190
+ }
191
+ /** Fetch an actor's public profile. */
192
+ async getProfile(actor, ctx) {
193
+ const raw = await this.get('app.bsky.actor.getProfile', { actor }, ctx);
194
+ return normalizeActor(raw);
195
+ }
196
+ /** Get an author's recent feed. */
197
+ async getAuthorFeed(params, ctx) {
198
+ const raw = await this.get('app.bsky.feed.getAuthorFeed', {
199
+ actor: params.actor,
200
+ ...(params.filter ? { filter: params.filter } : {}),
201
+ limit: params.limit ?? 25,
202
+ ...(params.cursor ? { cursor: params.cursor } : {}),
203
+ }, ctx);
204
+ return {
205
+ feed: (raw.feed ?? []).map((item) => normalizePost(item.post)),
206
+ ...(raw.cursor ? { cursor: raw.cursor } : {}),
207
+ };
208
+ }
209
+ /** Fetch the full conversation thread for a post by AT-URI. */
210
+ async getPostThread(params, ctx) {
211
+ const raw = await this.get('app.bsky.feed.getPostThread', {
212
+ uri: params.uri,
213
+ depth: params.depth ?? 6,
214
+ parentHeight: params.parentHeight ?? 80,
215
+ }, ctx);
216
+ return normalizeThread(raw.thread);
217
+ }
218
+ /** Search for actors by name / handle fragment. */
219
+ async searchActors(params, ctx) {
220
+ const raw = await this.get('app.bsky.actor.searchActors', {
221
+ q: params.q,
222
+ limit: params.limit ?? 25,
223
+ ...(params.cursor ? { cursor: params.cursor } : {}),
224
+ }, ctx);
225
+ return {
226
+ actors: (raw.actors ?? []).map(normalizeActor),
227
+ ...(raw.cursor ? { cursor: raw.cursor } : {}),
228
+ };
229
+ }
230
+ /** Get followers of an actor. */
231
+ async getFollowers(params, ctx) {
232
+ const raw = await this.get('app.bsky.graph.getFollowers', {
233
+ actor: params.actor,
234
+ limit: params.limit ?? 25,
235
+ ...(params.cursor ? { cursor: params.cursor } : {}),
236
+ }, ctx);
237
+ return {
238
+ actors: (raw.followers ?? []).map(normalizeActor),
239
+ subject: normalizeActor(raw.subject),
240
+ ...(raw.cursor ? { cursor: raw.cursor } : {}),
241
+ };
242
+ }
243
+ /** Get accounts an actor follows. */
244
+ async getFollows(params, ctx) {
245
+ const raw = await this.get('app.bsky.graph.getFollows', {
246
+ actor: params.actor,
247
+ limit: params.limit ?? 25,
248
+ ...(params.cursor ? { cursor: params.cursor } : {}),
249
+ }, ctx);
250
+ return {
251
+ actors: (raw.follows ?? []).map(normalizeActor),
252
+ subject: normalizeActor(raw.subject),
253
+ ...(raw.cursor ? { cursor: raw.cursor } : {}),
254
+ };
255
+ }
256
+ /** Fetch real-time trending topics (app.bsky.unspecced.getTrends — unspecced endpoint, may change). */
257
+ async getTrends(params, ctx) {
258
+ const raw = await this.get('app.bsky.unspecced.getTrends', { limit: params.limit ?? 10 }, ctx);
259
+ return {
260
+ trends: (raw.trends ?? []).map((t) => ({
261
+ topic: t.topic,
262
+ displayName: t.displayName ?? t.topic,
263
+ ...(t.link ? { link: t.link } : {}),
264
+ ...(t.startedAt ? { startedAt: t.startedAt } : {}),
265
+ ...(typeof t.postCount === 'number' ? { postCount: t.postCount } : {}),
266
+ ...(t.status ? { status: t.status } : {}),
267
+ ...(t.category ? { category: t.category } : {}),
268
+ })),
269
+ };
270
+ }
271
+ }
272
+ // ---------------------------------------------------------------------------
273
+ // Init / accessor pattern
274
+ // ---------------------------------------------------------------------------
275
+ let _service;
276
+ /** Initialize the BlueskyService singleton. Call once in createApp setup(). */
277
+ export function initBlueskyService() {
278
+ _service = new BlueskyService();
279
+ }
280
+ /** Get the initialized BlueskyService singleton. Throws if not yet initialized. */
281
+ export function getBlueskyService() {
282
+ if (!_service) {
283
+ throw new Error('BlueskyService not initialized — call initBlueskyService() in setup()');
284
+ }
285
+ return _service;
286
+ }
287
+ //# sourceMappingURL=bluesky-service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bluesky-service.js","sourceRoot":"","sources":["../../../src/services/bluesky/bluesky-service.ts"],"names":[],"mappings":"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"}